Android: Fix local ref handling.

We where allowing conversion from jobject to QJNIObject without taking
ownership of the jobject. Since we are managing the JNI environment we
should not allow conversions without having the option of taking
ownership of the local ref. This is now done by making the conversions
explicit, i.e., local refs are converted through
QJNIObjectPrivate::fromLocalRef() and global refs through the
QJNIObjectPrivate's jobject constructor.

This change breaks SC, but the API is private and no usage have been
found outside QtBase.

Change-Id: I3175f171699ec3f8e65144aaebc6246bc6e5bb4d
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
This commit is contained in:
Christian Strømme 2015-02-13 12:18:33 +01:00 committed by Christian Stromme
parent 921dd85c7a
commit 02c5657a7d
4 changed files with 18 additions and 6 deletions

View File

@ -57,7 +57,7 @@ static QJNIObjectPrivate applicationContext()
if (appCtx.isValid()) if (appCtx.isValid())
return appCtx; return appCtx;
QJNIObjectPrivate activity = QtAndroidPrivate::activity(); QJNIObjectPrivate activity(QtAndroidPrivate::activity());
if (!activity.isValid()) if (!activity.isValid())
return appCtx; return appCtx;
@ -131,7 +131,7 @@ static QString getExternalFilesDir(const char *directoryField = 0)
if (!path.isEmpty()) if (!path.isEmpty())
return path; return path;
QJNIObjectPrivate activity = QtAndroidPrivate::activity(); QJNIObjectPrivate activity(QtAndroidPrivate::activity());
if (!activity.isValid()) if (!activity.isValid())
return QString(); return QString();

View File

@ -96,7 +96,7 @@ static jclass loadClassDotEnc(const QString &classDotEnc, JNIEnv *env)
if (clazz != 0 || isCached) if (clazz != 0 || isCached)
return clazz; return clazz;
QJNIObjectPrivate classLoader = QtAndroidPrivate::classLoader(); QJNIObjectPrivate classLoader(QtAndroidPrivate::classLoader());
if (!classLoader.isValid()) if (!classLoader.isValid())
return 0; return 0;
@ -2239,6 +2239,13 @@ bool QJNIObjectPrivate::isValid() const
return d->m_jobject; return d->m_jobject;
} }
QJNIObjectPrivate QJNIObjectPrivate::fromLocalRef(jobject lref)
{
QJNIObjectPrivate o(lref);
QJNIEnvironmentPrivate()->DeleteLocalRef(lref);
return o;
}
bool QJNIObjectPrivate::isSameObject(jobject obj) const bool QJNIObjectPrivate::isSameObject(jobject obj) const
{ {
QJNIEnvironmentPrivate env; QJNIEnvironmentPrivate env;

View File

@ -84,7 +84,10 @@ public:
QJNIObjectPrivate(const char *className, const char *sig, ...); QJNIObjectPrivate(const char *className, const char *sig, ...);
explicit QJNIObjectPrivate(jclass clazz); explicit QJNIObjectPrivate(jclass clazz);
QJNIObjectPrivate(jclass clazz, const char *sig, ...); QJNIObjectPrivate(jclass clazz, const char *sig, ...);
QJNIObjectPrivate(jobject obj); // In most cases you should never call this function with a local ref. unless you intend
// to manage the local ref. yourself.
// NOTE: see fromLocalRef() for converting a local ref. to QJNIObjectPrivate.
explicit QJNIObjectPrivate(jobject globalRef);
template <typename T> template <typename T>
T callMethod(const char *methodName, T callMethod(const char *methodName,
@ -183,6 +186,9 @@ public:
return *this; return *this;
} }
// This function takes ownership of the jobject and releases the local ref. before returning.
static QJNIObjectPrivate fromLocalRef(jobject lref);
private: private:
friend class QAndroidJniObject; friend class QAndroidJniObject;

View File

@ -295,8 +295,7 @@ QList<AndroidNetworkInfo> AndroidConnectivityManager::getAllNetworkInfo() const
if (exceptionCheckAndClear(env)) if (exceptionCheckAndClear(env))
break; break;
list << AndroidNetworkInfo(lref); list << AndroidNetworkInfo(QJNIObjectPrivate::fromLocalRef(lref));
env->DeleteLocalRef(lref);
} }
return list; return list;