diff options
7 files changed, 178 insertions, 29 deletions
diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 861eeea3bc34..fdd64f96701c 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -263,14 +263,14 @@ public class Tuner implements AutoCloseable { } private void setFrontendInfoList() { - List<Integer> ids = nativeGetFrontendIds(); + List<Integer> ids = getFrontendIds(); if (ids == null) { return; } TunerFrontendInfo[] infos = new TunerFrontendInfo[ids.size()]; for (int i = 0; i < ids.size(); i++) { int id = ids.get(i); - FrontendInfo frontendInfo = nativeGetFrontendInfo(id); + FrontendInfo frontendInfo = getFrontendInfoById(id); if (frontendInfo == null) { continue; } @@ -281,6 +281,11 @@ public class Tuner implements AutoCloseable { mTunerResourceManager.setFrontendInfoList(infos); } + /** @hide */ + public List<Integer> getFrontendIds() { + return nativeGetFrontendIds(); + } + private void setLnbIds() { int[] ids = nativeGetLnbIds(); if (ids == null) { @@ -345,14 +350,17 @@ public class Tuner implements AutoCloseable { @Override public void close() { if (mFrontendHandle != null) { + nativeCloseFrontendByHandle(mFrontendHandle); mTunerResourceManager.releaseFrontend(mFrontendHandle); mFrontendHandle = null; + mFrontend = null; } if (mLnb != null) { mTunerResourceManager.releaseLnb(mLnbHandle); mLnb = null; + mLnbHandle = null; } - nativeClose(); + TunerUtils.throwExceptionForResult(nativeClose(), "failed to close tuner"); } /** @@ -374,6 +382,8 @@ public class Tuner implements AutoCloseable { * Native method to open frontend of the given ID. */ private native Frontend nativeOpenFrontendByHandle(int handle); + @Result + private native int nativeCloseFrontendByHandle(int handle); private native int nativeTune(int type, FrontendSettings settings); private native int nativeStopTune(); private native int nativeScan(int settingsType, FrontendSettings settings, int scanType); @@ -522,6 +532,7 @@ public class Tuner implements AutoCloseable { public int tune(@NonNull FrontendSettings settings) { mFrontendType = settings.getType(); checkResource(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND); + mFrontendInfo = null; return nativeTune(settings.getType(), settings); } @@ -706,11 +717,16 @@ public class Tuner implements AutoCloseable { throw new IllegalStateException("frontend is not initialized"); } if (mFrontendInfo == null) { - mFrontendInfo = nativeGetFrontendInfo(mFrontend.mId); + mFrontendInfo = getFrontendInfoById(mFrontend.mId); } return mFrontendInfo; } + /** @hide */ + public FrontendInfo getFrontendInfoById(int id) { + return nativeGetFrontendInfo(id); + } + /** * Gets Demux capabilities. * diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java index 2c8899cfca78..a9f3dcf150cb 100644 --- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java @@ -416,11 +416,11 @@ public class TunerResourceManager { * <p><strong>Note:</strong> {@link #setFrontendInfoList(TunerFrontendInfo[])} must be called * before this release. * - * @param frontendId the id of the released frontend. + * @param frontendHandle the handle of the released frontend. */ - public void releaseFrontend(int frontendId) { + public void releaseFrontend(int frontendHandle) { try { - mService.releaseFrontend(frontendId); + mService.releaseFrontend(frontendHandle); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index 7579ca58b37b..909394fbc495 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -833,6 +833,12 @@ JTuner::JTuner(JNIEnv *env, jobject thiz) } JTuner::~JTuner() { + if (mFe != NULL) { + mFe->close(); + } + if (mDemux != NULL) { + mDemux->close(); + } JNIEnv *env = AndroidRuntime::getJNIEnv(); env->DeleteWeakGlobalRef(mObject); @@ -908,6 +914,14 @@ jobject JTuner::openFrontendById(int id) { (jint) jId); } +jint JTuner::closeFrontendById(int id) { + if (mFe != NULL && mFeId == id) { + Result r = mFe->close(); + return (jint) r; + } + return (jint) Result::SUCCESS; +} + jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V"); @@ -1271,6 +1285,23 @@ Result JTuner::openDemux() { return res; } +jint JTuner::close() { + Result res = Result::SUCCESS; + if (mFe != NULL) { + res = mFe->close(); + if (res != Result::SUCCESS) { + return (jint) res; + } + } + if (mDemux != NULL) { + res = mDemux->close(); + if (res != Result::SUCCESS) { + return (jint) res; + } + } + return (jint) res; +} + jobject JTuner::getAvSyncHwId(sp<Filter> filter) { if (mDemux == NULL) { return NULL; @@ -2362,6 +2393,13 @@ static jobject android_media_tv_Tuner_open_frontend_by_handle( return tuner->openFrontendById(id); } +static jint android_media_tv_Tuner_close_frontend_by_handle( + JNIEnv *env, jobject thiz, jint handle) { + sp<JTuner> tuner = getTuner(env, thiz); + uint32_t id = getResourceIdFromHandle(handle); + return tuner->closeFrontendById(id); +} + static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) { sp<JTuner> tuner = getTuner(env, thiz); return tuner->tune(getFrontendSettings(env, type, settings)); @@ -3135,6 +3173,11 @@ static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint /* return (jint) tuner->openDemux(); } +static jint android_media_tv_Tuner_close_tuner(JNIEnv* env, jobject thiz) { + sp<JTuner> tuner = getTuner(env, thiz); + return (jint) tuner->close(); +} + static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { @@ -3424,6 +3467,8 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_get_frontend_ids }, { "nativeOpenFrontendByHandle", "(I)Landroid/media/tv/tuner/Tuner$Frontend;", (void *)android_media_tv_Tuner_open_frontend_by_handle }, + { "nativeCloseFrontendByHandle", "(I)I", + (void *)android_media_tv_Tuner_close_frontend_by_handle }, { "nativeTune", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;)I", (void *)android_media_tv_Tuner_tune }, { "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune }, @@ -3460,6 +3505,7 @@ static const JNINativeMethod gTunerMethods[] = { { "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;", (void *)android_media_tv_Tuner_get_demux_caps }, { "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux }, + {"nativeClose", "()I", (void *)android_media_tv_Tuner_close_tuner }, }; static const JNINativeMethod gFilterMethods[] = { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 6749ba085739..750b146dbd59 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -172,6 +172,7 @@ struct JTuner : public RefBase { int disconnectCiCam(); jobject getFrontendIds(); jobject openFrontendById(int id); + jint closeFrontendById(int id); jobject getFrontendInfo(int id); int tune(const FrontendSettings& settings); int stopTune(); @@ -189,6 +190,7 @@ struct JTuner : public RefBase { jobject getDemuxCaps(); jobject getFrontendStatus(jintArray types); Result openDemux(); + jint close(); protected: virtual ~JTuner(); diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java index e100ff816f00..dfd23df40374 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java @@ -131,7 +131,7 @@ public final class ClientProfile { mUsingFrontendIds.add(frontendId); } - public Iterable<Integer> getInUseFrontendIds() { + public Set<Integer> getInUseFrontendIds() { return mUsingFrontendIds; } diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java index 6dded00321b5..fd2445f8366e 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -243,15 +243,20 @@ public class TunerResourceManagerService extends SystemService { if (DEBUG) { Slog.d(TAG, "requestLnb(request=" + request + ")"); } + return true; } @Override - public void releaseFrontend(int frontendId) { + public void releaseFrontend(int frontendHandle) throws RemoteException { enforceTunerAccessPermission("releaseFrontend"); enforceTrmAccessPermission("releaseFrontend"); - if (DEBUG) { - Slog.d(TAG, "releaseFrontend(id=" + frontendId + ")"); + if (!validateResourceHandle(TunerResourceManager.TUNER_RESOURCE_TYPE_FRONTEND, + frontendHandle)) { + throw new RemoteException("frontendHandle can't be invalid"); + } + synchronized (mLock) { + releaseFrontendInternal(getResourceIdFromHandle(frontendHandle)); } } @@ -393,7 +398,6 @@ public class TunerResourceManagerService extends SystemService { } } - // TODO check if the removing resource is in use or not. Handle the conflict. for (int removingId : updatingFrontendIds) { // update the exclusive group id member list removeFrontendResource(removingId); @@ -464,6 +468,14 @@ public class TunerResourceManagerService extends SystemService { } @VisibleForTesting + void releaseFrontendInternal(int frontendId) { + if (DEBUG) { + Slog.d(TAG, "releaseFrontend(id=" + frontendId + ")"); + } + updateFrontendClientMappingOnRelease(frontendId); + } + + @VisibleForTesting boolean requestDemuxInternal(TunerDemuxRequest request, int[] demuxHandle) { if (DEBUG) { Slog.d(TAG, "requestDemux(request=" + request + ")"); @@ -568,6 +580,17 @@ public class TunerResourceManagerService extends SystemService { } } + private void updateFrontendClientMappingOnRelease(int frontendId) { + FrontendResource releasingFrontend = getFrontendResource(frontendId); + ClientProfile ownerProfile = getClientProfile(releasingFrontend.getOwnerClientId()); + releasingFrontend.removeOwner(); + ownerProfile.releaseFrontend(frontendId); + for (int exclusiveGroupMember : releasingFrontend.getExclusiveGroupMemberFeIds()) { + getFrontendResource(exclusiveGroupMember).removeOwner(); + ownerProfile.releaseFrontend(exclusiveGroupMember); + } + } + /** * Get the owner client's priority from the frontend id. * @@ -609,6 +632,9 @@ public class TunerResourceManagerService extends SystemService { private void removeFrontendResource(int removingId) { FrontendResource fe = getFrontendResource(removingId); + if (fe.isInUse()) { + releaseFrontendInternal(removingId); + } for (int excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) { getFrontendResource(excGroupmemberFeId) .removeExclusiveGroupMemberFeId(fe.getId()); @@ -651,6 +677,22 @@ public class TunerResourceManagerService extends SystemService { | (mResourceRequestCount++ & 0xffff); } + @VisibleForTesting + protected int getResourceIdFromHandle(int resourceHandle) { + if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) { + return resourceHandle; + } + return (resourceHandle & 0x00ff0000) >> 16; + } + + private boolean validateResourceHandle(int resourceType, int resourceHandle) { + if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE + || ((resourceHandle & 0xff000000) >> 24) != resourceType) { + return false; + } + return true; + } + private void enforceTrmAccessPermission(String apiName) { getContext().enforceCallingPermission("android.permission.TUNER_RESOURCE_ACCESS", TAG + ": " + apiName); diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java index fcbd5072ae35..13248a00c1b0 100644 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/TunerResourceManagerServiceTest.java @@ -96,13 +96,6 @@ public class TunerResourceManagerServiceTest { } }; - private static int getResourceIdFromHandle(int resourceHandle) { - if (resourceHandle == TunerResourceManager.INVALID_RESOURCE_HANDLE) { - return resourceHandle; - } - return (resourceHandle & 0x00ff0000) >> 16; - } - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -247,7 +240,7 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])) + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) .isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE); } @@ -275,7 +268,7 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])) + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) .isEqualTo(TunerResourceManager.INVALID_RESOURCE_HANDLE); } @@ -307,7 +300,8 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(0); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(0); } @Test @@ -344,7 +338,8 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[0].getId()); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(infos[0].getId()); request = new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT); @@ -354,7 +349,8 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[1].getId()); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(infos[1].getId()); assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) .isInUse()).isTrue(); assertThat(mTunerResourceManagerService.getFrontendResource(infos[2].getId()) @@ -464,7 +460,8 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[0].getId()); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(infos[0].getId()); request = new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS); @@ -474,7 +471,8 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[1].getId()); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(infos[1].getId()); assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId()) .isInUse()).isTrue(); assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) @@ -487,6 +485,49 @@ public class TunerResourceManagerServiceTest { } @Test + public void releaseFrontendTest_UnderTheSameExclusiveGroup() { + // Register clients + ResourceClientProfile[] profiles = new ResourceClientProfile[1]; + profiles[0] = new ResourceClientProfile("0" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + int[] clientId = new int[1]; + TestResourcesReclaimListener listener = new TestResourcesReclaimListener(); + mTunerResourceManagerService.registerClientProfileInternal(profiles[0], listener, clientId); + assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + + // Init frontend resources. + TunerFrontendInfo[] infos = new TunerFrontendInfo[2]; + infos[0] = + new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + infos[1] = + new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/); + mTunerResourceManagerService.setFrontendInfoListInternal(infos); + + TunerFrontendRequest request = + new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + int[] frontendHandle = new int[1]; + try { + assertThat(mTunerResourceManagerService + .requestFrontendInternal(request, frontendHandle)).isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + int frontendId = mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0]); + assertThat(frontendId).isEqualTo(infos[0].getId()); + assertThat(mTunerResourceManagerService + .getFrontendResource(infos[1].getId()).isInUse()).isTrue(); + + // Release frontend + mTunerResourceManagerService.releaseFrontendInternal(frontendId); + assertThat(mTunerResourceManagerService + .getFrontendResource(frontendId).isInUse()).isFalse(); + assertThat(mTunerResourceManagerService + .getFrontendResource(infos[1].getId()).isInUse()).isFalse(); + assertThat(mTunerResourceManagerService + .getClientProfile(clientId[0]).getInUseFrontendIds().size()).isEqualTo(0); + } + + @Test public void unregisterClientTest_usingFrontend() { // Register client ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/, @@ -513,7 +554,8 @@ public class TunerResourceManagerServiceTest { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - assertThat(getResourceIdFromHandle(frontendHandle[0])).isEqualTo(infos[0].getId()); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(frontendHandle[0])) + .isEqualTo(infos[0].getId()); assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].getId()) .isInUse()).isTrue(); assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) @@ -543,7 +585,8 @@ public class TunerResourceManagerServiceTest { TunerDemuxRequest request = new TunerDemuxRequest(clientId[0]); assertThat(mTunerResourceManagerService.requestDemuxInternal(request, demuxHandle)) .isTrue(); - assertThat(getResourceIdFromHandle(demuxHandle[0])).isEqualTo(0); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(demuxHandle[0])) + .isEqualTo(0); } @Test @@ -560,6 +603,6 @@ public class TunerResourceManagerServiceTest { TunerDescramblerRequest request = new TunerDescramblerRequest(clientId[0]); assertThat(mTunerResourceManagerService.requestDescramblerInternal(request, desHandle)) .isTrue(); - assertThat(getResourceIdFromHandle(desHandle[0])).isEqualTo(0); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(desHandle[0])).isEqualTo(0); } } |