DRM framwork bug fix: add an API to release resources

When DrmManagerClient object is created and released many times,
the process suddenly crashes.
The case can happen when we make many thumbnails of
DRM-encrypted contents.

The problem is caused by shortage of file descriptors.
DrmManagerClient releases references of file descriptors
only when GC runs. So file descriptors are kept long time
even after the reference of DrmManagerClient are released.

By introducing DrmManagerClient#release() API,
the problem is solved. An application call this API
when we no longer need to use DrmManagerClient object.

Changes are made by SEMC and Sony.

Change-Id: Ie0bbc29cc33872449824285a8d67b1c3cdd8082b
This commit is contained in:
Kei Takahashi
2012-01-31 13:18:45 +09:00
parent d7fa7deef9
commit 6225df0103
3 changed files with 86 additions and 27 deletions

View File

@@ -7494,6 +7494,7 @@ package android.drm {
method public java.lang.String getOriginalMimeType(android.net.Uri);
method public int openConvertSession(java.lang.String);
method public int processDrmInfo(android.drm.DrmInfo);
method public void release();
method public int removeAllRights();
method public int removeRights(java.lang.String);
method public int removeRights(android.net.Uri);

View File

@@ -49,6 +49,8 @@ public class DrmManagerClient {
*/
public static final int ERROR_UNKNOWN = -2000;
HandlerThread mInfoThread;
HandlerThread mEventThread;
private static final String TAG = "DrmManagerClient";
static {
@@ -105,6 +107,7 @@ public class DrmManagerClient {
private int mUniqueId;
private int mNativeContext;
private boolean mReleased;
private Context mContext;
private InfoHandler mInfoHandler;
private EventHandler mEventHandler;
@@ -238,23 +241,63 @@ public class DrmManagerClient {
*/
public DrmManagerClient(Context context) {
mContext = context;
HandlerThread infoThread = new HandlerThread("DrmManagerClient.InfoHandler");
infoThread.start();
mInfoHandler = new InfoHandler(infoThread.getLooper());
HandlerThread eventThread = new HandlerThread("DrmManagerClient.EventHandler");
eventThread.start();
mEventHandler = new EventHandler(eventThread.getLooper());
mReleased = false;
// save the unique id
mUniqueId = _initialize(new WeakReference<DrmManagerClient>(this));
mUniqueId = _initialize();
}
protected void finalize() {
_finalize(mUniqueId);
if (!mReleased) {
Log.w(TAG, "You should have called release()");
release();
}
}
/**
* Releases resources associated with the current session of DrmManagerClient.
*
* It is considered good practice to call this method when the {@link DrmManagerClient} object
* is no longer needed in your application. After release() is called,
* {@link DrmManagerClient} is no longer usable since it has lost all of its required resource.
*/
public void release() {
if (mReleased) {
Log.w(TAG, "You have already called release()");
return;
}
mReleased = true;
if (mEventHandler != null) {
mEventThread.quit();
mEventThread = null;
}
if (mInfoHandler != null) {
mInfoThread.quit();
mInfoThread = null;
}
mEventHandler = null;
mInfoHandler = null;
mOnEventListener = null;
mOnInfoListener = null;
mOnErrorListener = null;
_release(mUniqueId);
}
private void createListeners() {
if (mEventHandler == null && mInfoHandler == null) {
mInfoThread = new HandlerThread("DrmManagerClient.InfoHandler");
mInfoThread.start();
mInfoHandler = new InfoHandler(mInfoThread.getLooper());
mEventThread = new HandlerThread("DrmManagerClient.EventHandler");
mEventThread.start();
mEventHandler = new EventHandler(mEventThread.getLooper());
_setListeners(mUniqueId, new WeakReference<DrmManagerClient>(this));
}
}
/**
* Registers an {@link DrmManagerClient.OnInfoListener} callback, which is invoked when the
* DRM framework sends status or warning information during registration or rights acquisition.
@@ -262,8 +305,9 @@ public class DrmManagerClient {
* @param infoListener Interface definition for the callback.
*/
public synchronized void setOnInfoListener(OnInfoListener infoListener) {
mOnInfoListener = infoListener;
if (null != infoListener) {
mOnInfoListener = infoListener;
createListeners();
}
}
@@ -274,8 +318,9 @@ public class DrmManagerClient {
* @param eventListener Interface definition for the callback.
*/
public synchronized void setOnEventListener(OnEventListener eventListener) {
mOnEventListener = eventListener;
if (null != eventListener) {
mOnEventListener = eventListener;
createListeners();
}
}
@@ -286,8 +331,9 @@ public class DrmManagerClient {
* @param errorListener Interface definition for the callback.
*/
public synchronized void setOnErrorListener(OnErrorListener errorListener) {
mOnErrorListener = errorListener;
if (null != errorListener) {
mOnErrorListener = errorListener;
createListeners();
}
}
@@ -792,9 +838,11 @@ public class DrmManagerClient {
}
// private native interfaces
private native int _initialize(Object weak_this);
private native int _initialize();
private native void _finalize(int uniqueId);
private native void _setListeners(int uniqueId, Object weak_this);
private native void _release(int uniqueId);
private native void _installDrmEngine(int uniqueId, String engineFilepath);

View File

@@ -225,25 +225,32 @@ static sp<DrmManagerClientImpl> getDrmManagerClientImpl(JNIEnv* env, jobject thi
}
static jint android_drm_DrmManagerClient_initialize(
JNIEnv* env, jobject thiz, jobject weak_thiz) {
JNIEnv* env, jobject thiz) {
ALOGV("initialize - Enter");
int uniqueId = 0;
sp<DrmManagerClientImpl> drmManager = DrmManagerClientImpl::create(&uniqueId, false);
drmManager->addClient(uniqueId);
// Set the listener to DrmManager
sp<DrmManagerClient::OnInfoListener> listener = new JNIOnInfoListener(env, thiz, weak_thiz);
drmManager->setOnInfoListener(uniqueId, listener);
setDrmManagerClientImpl(env, thiz, drmManager);
ALOGV("initialize - Exit");
return uniqueId;
}
static void android_drm_DrmManagerClient_finalize(JNIEnv* env, jobject thiz, jint uniqueId) {
ALOGV("finalize - Enter");
static void android_drm_DrmManagerClient_setListeners(
JNIEnv* env, jobject thiz, jint uniqueId, jobject weak_thiz) {
ALOGV("setListeners - Enter");
// Set the listener to DrmManager
sp<DrmManagerClient::OnInfoListener> listener = new JNIOnInfoListener(env, thiz, weak_thiz);
getDrmManagerClientImpl(env, thiz)->setOnInfoListener(uniqueId, listener);
ALOGV("setListeners - Exit");
}
static void android_drm_DrmManagerClient_release(
JNIEnv* env, jobject thiz, jint uniqueId) {
ALOGV("release - Enter");
DrmManagerClientImpl::remove(uniqueId);
getDrmManagerClientImpl(env, thiz)->setOnInfoListener(uniqueId, NULL);
@@ -252,7 +259,7 @@ static void android_drm_DrmManagerClient_finalize(JNIEnv* env, jobject thiz, jin
oldClient->setOnInfoListener(uniqueId, NULL);
oldClient->removeClient(uniqueId);
}
ALOGV("finalize - Exit");
ALOGV("release - Exit");
}
static jobject android_drm_DrmManagerClient_getConstraintsFromContent(
@@ -714,11 +721,14 @@ static jobject android_drm_DrmManagerClient_closeConvertSession(
static JNINativeMethod nativeMethods[] = {
{"_initialize", "(Ljava/lang/Object;)I",
{"_initialize", "()I",
(void*)android_drm_DrmManagerClient_initialize},
{"_finalize", "(I)V",
(void*)android_drm_DrmManagerClient_finalize},
{"_setListeners", "(ILjava/lang/Object;)V",
(void*)android_drm_DrmManagerClient_setListeners},
{"_release", "(I)V",
(void*)android_drm_DrmManagerClient_release},
{"_getConstraints", "(ILjava/lang/String;I)Landroid/content/ContentValues;",
(void*)android_drm_DrmManagerClient_getConstraintsFromContent},