diff options
10 files changed, 413 insertions, 28 deletions
diff --git a/core/api/current.txt b/core/api/current.txt index e6c2b3bb635c..c31928dc013e 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -22668,7 +22668,6 @@ package android.media { method public void sendEvent(int, int, @Nullable byte[]) throws android.media.MediaCasException; method public void setEventListener(@Nullable android.media.MediaCas.EventListener, @Nullable android.os.Handler); method public void setPrivateData(@NonNull byte[]) throws android.media.MediaCasException; - method @FlaggedApi("com.android.media.flags.update_client_profile_priority") public boolean updateResourcePriority(int, int); field public static final int PLUGIN_STATUS_PHYSICAL_MODULE_CHANGED = 0; // 0x0 field public static final int PLUGIN_STATUS_SESSION_NUMBER_CHANGED = 1; // 0x1 field public static final int SCRAMBLING_MODE_AES128 = 9; // 0x9 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 06289848138b..261c2ae30780 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -7581,6 +7581,11 @@ package android.media { method @NonNull public android.media.HwAudioSource.Builder setAudioDeviceInfo(@NonNull android.media.AudioDeviceInfo); } + public final class MediaCas implements java.lang.AutoCloseable { + method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceHolderRetain(boolean); + method @FlaggedApi("com.android.media.flags.update_client_profile_priority") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public boolean updateResourcePriority(int, int); + } + public final class MediaCodec { method @NonNull @RequiresPermission(android.Manifest.permission.MEDIA_RESOURCE_OVERRIDE_PID) public static android.media.MediaCodec createByCodecNameForClient(@NonNull String, int, int) throws java.io.IOException; } @@ -8353,6 +8358,7 @@ package android.media.tv.tuner { method public int setLnaEnabled(boolean); method public int setMaxNumberOfFrontends(int, @IntRange(from=0) int); method public void setOnTuneEventListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.frontend.OnTuneEventListener); + method @FlaggedApi("android.media.tv.flags.set_resource_holder_retain") @RequiresPermission("android.permission.TUNER_RESOURCE_ACCESS") public void setResourceHolderRetain(boolean); method public void setResourceLostListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.tv.tuner.Tuner.OnResourceLostListener); method public void shareFrontendFromTuner(@NonNull android.media.tv.tuner.Tuner); method public int transferOwner(@NonNull android.media.tv.tuner.Tuner); diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java index 8b31588ede1a..88efed55c11f 100644 --- a/media/java/android/media/MediaCas.java +++ b/media/java/android/media/MediaCas.java @@ -16,12 +16,16 @@ package android.media; +import static android.media.tv.flags.Flags.FLAG_SET_RESOURCE_HOLDER_RETAIN; + import static com.android.media.flags.Flags.FLAG_UPDATE_CLIENT_PROFILE_PRIORITY; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.TestApi; import android.content.Context; import android.hardware.cas.AidlCasPluginDescriptor; @@ -990,12 +994,32 @@ public final class MediaCas implements AutoCloseable { * @param priority the new priority. Any negative value would cause no-op on priority setting * and the API would only process nice value setting in that case. * @param niceValue the nice value. + * @hide */ @FlaggedApi(FLAG_UPDATE_CLIENT_PROFILE_PRIORITY) + @SystemApi + @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS) public boolean updateResourcePriority(int priority, int niceValue) { return mTunerResourceManager.updateClientPriority(mClientId, priority, niceValue); } + /** + * Determines whether the resource holder retains ownership of the resource during a challenge + * scenario, when both resource holder and resource challenger have same processId and same + * priority. + * + * @param resourceHolderRetain Set to {@code true} to allow the resource holder to retain + * ownership, or false to allow the resource challenger to acquire the resource. + * If not explicitly set, resourceHolderRetain is set to {@code false}. + * @hide + */ + @FlaggedApi(FLAG_SET_RESOURCE_HOLDER_RETAIN) + @SystemApi + @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS) + public void setResourceHolderRetain(boolean resourceHolderRetain) { + mTunerResourceManager.setResourceHolderRetain(mClientId, resourceHolderRetain); + } + IHwBinder getBinder() { if (mICas != null) { return null; // Return IHwBinder only for HIDL diff --git a/media/java/android/media/tv/flags/media_tv.aconfig b/media/java/android/media/tv/flags/media_tv.aconfig index d49f7dd92bf7..4de68634af5e 100644 --- a/media/java/android/media/tv/flags/media_tv.aconfig +++ b/media/java/android/media/tv/flags/media_tv.aconfig @@ -71,4 +71,12 @@ flag { namespace: "media_tv" description: "Standardize AIDL Extension Interface of TIS" bug: "330366987" -}
\ No newline at end of file +} + +flag { + name: "set_resource_holder_retain" + is_exported: true + namespace: "media_tv" + description : "Feature flag to add setResourceHolderRetain api to MediaCas and Tuner JAVA." + bug: "372973197" +} diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index cdf50ec963d8..b1adb77f9543 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -16,6 +16,8 @@ package android.media.tv.tuner; +import static android.media.tv.flags.Flags.FLAG_SET_RESOURCE_HOLDER_RETAIN; + import android.annotation.BytesLong; import android.annotation.CallbackExecutor; import android.annotation.FlaggedApi; @@ -751,6 +753,21 @@ public class Tuner implements AutoCloseable { } /** + * Determines whether the resource holder retains ownership of the resource during a challenge + * scenario, when both resource holder and resource challenger have same processId and same + * priority. + * + * @param resourceHolderRetain Set to true to allow the resource holder to retain ownership, or + * false to allow the resource challenger to acquire the resource. If not explicitly set, + * resourceHolderRetain is set to false. + */ + @FlaggedApi(FLAG_SET_RESOURCE_HOLDER_RETAIN) + @RequiresPermission(android.Manifest.permission.TUNER_RESOURCE_ACCESS) + public void setResourceHolderRetain(boolean resourceHolderRetain) { + mTunerResourceManager.setResourceHolderRetain(mClientId, resourceHolderRetain); + } + + /** * Checks if there is an unused frontend resource available. * * @param frontendType {@link android.media.tv.tuner.frontend.FrontendSettings.Type} for the diff --git a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java index bb581ebe1778..be65ad98c35b 100644 --- a/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java +++ b/media/java/android/media/tv/tunerresourcemanager/TunerResourceManager.java @@ -40,8 +40,11 @@ import java.util.concurrent.Executor; * <p>Resources include: * <ul> * <li>TunerFrontend {@link android.media.tv.tuner.frontend}. + * <li>Demux {@link com.android.server.tv.tunerresourcemanager.DemuxResource}. + * <li>Descrambler {@link android.media.tv.tuner.Descrambler}. * <li>TunerLnb {@link android.media.tv.tuner.Lnb}. * <li>MediaCas {@link android.media.MediaCas}. + * <li>CiCam {@link com.android.server.tv.tunerresourcemanager.CiCamResource}. * <ul> * * <p>Expected workflow is: @@ -78,7 +81,7 @@ public class TunerResourceManager { TUNER_RESOURCE_TYPE_LNB, TUNER_RESOURCE_TYPE_CAS_SESSION, TUNER_RESOURCE_TYPE_FRONTEND_CICAM, - TUNER_RESOURCE_TYPE_MAX, + TUNER_RESOURCE_TYPE_MAX, // upper bound of constants }) @Retention(RetentionPolicy.SOURCE) public @interface TunerResourceType {} @@ -220,6 +223,25 @@ public class TunerResourceManager { } /** + * Determines whether the resource holder retains ownership of the resource during a challenge + * scenario, when both resource holder and resource challenger have same processId and same + * priority. + * + * @param clientId The client id used to set ownership of resource to owner in case of resource + * challenger situation. + * @param resourceHolderRetain Set to true to allow the resource holder to retain ownership, or + * false to allow the resource challenger to acquire the resource. If not explicitly set, + * resourceHolderRetain is set to false. + */ + public void setResourceHolderRetain(int clientId, boolean resourceHolderRetain) { + try { + mService.setResourceHolderRetain(clientId, resourceHolderRetain); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Stores the frontend resource map if it was stored before. * * <p>This API is only for testing purpose and should be used in pair with diff --git a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl index 109c791c1748..c57be1b09b66 100644 --- a/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl +++ b/media/java/android/media/tv/tunerresourcemanager/aidl/android/media/tv/tunerresourcemanager/ITunerResourceManager.aidl @@ -151,6 +151,18 @@ interface ITunerResourceManager { */ void setLnbInfoList(in long[] lnbIds); + /** + * Determines whether the Resource Holder retains ownership of the resource during a challenge + * scenario, when both Resource Holder and Resource Challenger have same processId and same + * priority. + * + * @param clientId The resourceHolderRetain of the client is updated using client ID. + * @param resourceHolderRetain set to true to allow the Resource Holder to retain ownership, or + * false to allow the Resource Challenger to acquire the resource. If not explicitly set, + * resourceHolderRetain is set to false. + */ + void setResourceHolderRetain(int clientId, boolean resourceHolderRetain); + /* * This API is used by the Tuner framework to request a frontend from the TunerHAL. * 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 096231910e6e..38bc026c473a 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java @@ -115,11 +115,18 @@ public final class ClientProfile { */ private int mPriority; + /** + * If resource holder retains ownership of the resource in a challenge scenario then value is + * true. + */ + private boolean mResourceHolderRetain; + private ClientProfile(Builder builder) { this.mId = builder.mId; this.mTvInputSessionId = builder.mTvInputSessionId; this.mUseCase = builder.mUseCase; this.mProcessId = builder.mProcessId; + this.mResourceHolderRetain = builder.mResourceHolderRetain; } public int getId() { @@ -139,6 +146,14 @@ public final class ClientProfile { } /** + * Returns true when the resource holder retains ownership of the resource in a challenge + * scenario. + */ + public boolean shouldResourceHolderRetain() { + return mResourceHolderRetain; + } + + /** * If the client priority is overwrttien. */ public boolean isPriorityOverwritten() { @@ -180,6 +195,19 @@ public final class ClientProfile { } /** + * Determines whether the resource holder retains ownership of the resource during a challenge + * scenario, when both resource holder and resource challenger have same processId and same + * priority. + * + * @param resourceHolderRetain Set to true to allow the resource holder to retain ownership, or + * false (or resourceHolderRetain not set at all) to allow the resource challenger to + * acquire the resource. If not explicitly set, resourceHolderRetain is set to false. + */ + public void setResourceHolderRetain(boolean resourceHolderRetain) { + mResourceHolderRetain = resourceHolderRetain; + } + + /** * Set when the client starts to use a frontend. * * @param frontendHandle being used. @@ -361,6 +389,7 @@ public final class ClientProfile { private String mTvInputSessionId; private int mUseCase; private int mProcessId; + private boolean mResourceHolderRetain = false; Builder(int id) { this.mId = id; @@ -397,6 +426,18 @@ public final class ClientProfile { } /** + * Builder for {@link ClientProfile}. + * + * @param resourceHolderRetain the determining factor for resource ownership during + * challenger scenario. The default behavior favors the resource challenger and grants + * them ownership of the resource if resourceHolderRetain is not explicitly set to true. + */ + public Builder resourceHolderRetain(boolean resourceHolderRetain) { + this.mResourceHolderRetain = resourceHolderRetain; + return this; + } + + /** * Build a {@link ClientProfile}. * * @return {@link ClientProfile}. 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 c5b6bbf30ae1..5ae8c11f1d8f 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -16,6 +16,8 @@ package com.android.server.tv.tunerresourcemanager; +import static android.media.tv.flags.Flags.setResourceHolderRetain; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManager; @@ -229,6 +231,14 @@ public class TunerResourceManagerService extends SystemService implements IBinde } @Override + public void setResourceHolderRetain(int clientId, boolean resourceHolderRetain) { + enforceTrmAccessPermission("setResourceHolderRetain"); + synchronized (mLock) { + getClientProfile(clientId).setResourceHolderRetain(resourceHolderRetain); + } + } + + @Override public boolean isLowestPriority(int clientId, int frontendType) throws RemoteException { enforceTrmAccessPermission("isLowestPriority"); @@ -1066,8 +1076,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde // request client has higher priority. if (inUseLowestPriorityFrontend != null && ((requestClient.getPriority() > currentLowestPriority) - || ((requestClient.getPriority() == currentLowestPriority) - && isRequestFromSameProcess))) { + || ((requestClient.getPriority() == currentLowestPriority) + && isRequestFromSameProcess + && !(setResourceHolderRetain() + && requestClient.shouldResourceHolderRetain())))) { frontendHandle[0] = inUseLowestPriorityFrontend.getHandle(); reclaimOwnerId[0] = inUseLowestPriorityFrontend.getOwnerClientId(); return true; @@ -1249,9 +1261,11 @@ public class TunerResourceManagerService extends SystemService implements IBinde // When all the resources are occupied, grant the lowest priority resource if the // request client has higher priority. if (inUseLowestPriorityLnb != null - && ((requestClient.getPriority() > currentLowestPriority) || ( - (requestClient.getPriority() == currentLowestPriority) - && isRequestFromSameProcess))) { + && ((requestClient.getPriority() > currentLowestPriority) + || ((requestClient.getPriority() == currentLowestPriority) + && isRequestFromSameProcess + && !(setResourceHolderRetain() + && requestClient.shouldResourceHolderRetain())))) { lnbHandle[0] = inUseLowestPriorityLnb.getHandle(); reclaimOwnerId[0] = inUseLowestPriorityLnb.getOwnerClientId(); return true; @@ -1335,8 +1349,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde // request client has higher priority. if (lowestPriorityOwnerId != INVALID_CLIENT_ID && ((requestClient.getPriority() > currentLowestPriority) - || ((requestClient.getPriority() == currentLowestPriority) - && isRequestFromSameProcess))) { + || ((requestClient.getPriority() == currentLowestPriority) + && isRequestFromSameProcess + && !(setResourceHolderRetain() + && requestClient.shouldResourceHolderRetain())))) { casSessionHandle[0] = cas.getHandle(); reclaimOwnerId[0] = lowestPriorityOwnerId; return true; @@ -1420,8 +1436,10 @@ public class TunerResourceManagerService extends SystemService implements IBinde // request client has higher priority. if (lowestPriorityOwnerId != INVALID_CLIENT_ID && ((requestClient.getPriority() > currentLowestPriority) - || ((requestClient.getPriority() == currentLowestPriority) - && isRequestFromSameProcess))) { + || ((requestClient.getPriority() == currentLowestPriority) + && isRequestFromSameProcess + && !(setResourceHolderRetain() + && requestClient.shouldResourceHolderRetain())))) { ciCamHandle[0] = ciCam.getHandle(); reclaimOwnerId[0] = lowestPriorityOwnerId; return true; @@ -1655,9 +1673,11 @@ public class TunerResourceManagerService extends SystemService implements IBinde // When all the resources are occupied, grant the lowest priority resource if the // request client has higher priority. if (inUseLowestPriorityDemux != null - && ((requestClient.getPriority() > currentLowestPriority) || ( - (requestClient.getPriority() == currentLowestPriority) - && isRequestFromSameProcess))) { + && ((requestClient.getPriority() > currentLowestPriority) + || ((requestClient.getPriority() == currentLowestPriority) + && isRequestFromSameProcess + && !(setResourceHolderRetain() + && requestClient.shouldResourceHolderRetain())))) { demuxHandle[0] = inUseLowestPriorityDemux.getHandle(); reclaimOwnerId[0] = inUseLowestPriorityDemux.getOwnerClientId(); return true; 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 a222ef04ac30..5852af780b8b 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 @@ -15,6 +15,8 @@ */ package com.android.server.tv.tunerresourcemanager; +import static android.media.tv.flags.Flags.FLAG_SET_RESOURCE_HOLDER_RETAIN; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; @@ -39,7 +41,9 @@ import android.media.tv.tunerresourcemanager.TunerFrontendRequest; import android.media.tv.tunerresourcemanager.TunerLnbRequest; import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.os.RemoteException; +import android.platform.test.annotations.EnableFlags; import android.platform.test.annotations.Presubmit; +import android.platform.test.flag.junit.SetFlagsRule; import androidx.test.InstrumentationRegistry; import androidx.test.filters.SmallTest; @@ -47,6 +51,7 @@ import androidx.test.filters.SmallTest; import com.google.common.truth.Correspondence; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -70,6 +75,8 @@ public class TunerResourceManagerServiceTest { private TunerResourceManagerService mTunerResourceManagerService; private boolean mIsForeground; + @Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private final class TunerClient extends IResourcesReclaimListener.Stub { int[] mClientId; ClientProfile mProfile; @@ -125,19 +132,6 @@ public class TunerResourceManagerServiceTest { } } - private static final class TestResourcesReclaimListener extends IResourcesReclaimListener.Stub { - boolean mReclaimed; - - @Override - public void onReclaimResources() { - mReclaimed = true; - } - - public boolean isReclaimed() { - return mReclaimed; - } - } - // A correspondence to compare a FrontendResource and a TunerFrontendInfo. private static final Correspondence<FrontendResource, TunerFrontendInfo> FR_TFI_COMPARE = Correspondence.from((FrontendResource actual, TunerFrontendInfo expected) -> { @@ -485,6 +479,62 @@ public class TunerResourceManagerServiceTest { } @Test + @EnableFlags({FLAG_SET_RESOURCE_HOLDER_RETAIN}) + public void requestFrontendTest_NoFrontendAvailable_RequestWithEqualPriority() + throws RemoteException { + // Register clients + TunerClient client0 = new TunerClient(); + TunerClient client1 = new TunerClient(); + client0.register( + "0" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + client1.register( + "1" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + + // Init frontend resource. + TunerFrontendInfo[] infos = new TunerFrontendInfo[1]; + infos[0] = + tunerFrontendInfo(0 /*handle*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + mTunerResourceManagerService.setFrontendInfoListInternal(infos); + + // client0 requests for 1 frontend + TunerFrontendRequest request = + tunerFrontendRequest(client0.getId() /*clientId*/, FrontendSettings.TYPE_DVBT); + long[] frontendHandle = new long[1]; + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendHandle)) + .isTrue(); + assertThat(frontendHandle[0]).isEqualTo(infos[0].handle); + assertThat(client0.getProfile().getInUseFrontendHandles()) + .isEqualTo(new HashSet<Long>(Arrays.asList(infos[0].handle))); + + // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder + // (client0) to maintain ownership such as requester will not get the resources. + client1.getProfile().setResourceHolderRetain(true); + + request = tunerFrontendRequest(client1.getId() /*clientId*/, FrontendSettings.TYPE_DVBT); + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendHandle)) + .isFalse(); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle).isInUse()) + .isTrue(); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle) + .getOwnerClientId()) + .isEqualTo(client0.getId()); + assertThat(client0.isReclaimed()).isFalse(); + + // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource + // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the + // resources. + client1.getProfile().setResourceHolderRetain(false); + + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendHandle)) + .isTrue(); + assertThat(frontendHandle[0]).isEqualTo(infos[0].handle); + assertThat(mTunerResourceManagerService.getFrontendResource(infos[0].handle) + .getOwnerClientId()) + .isEqualTo(client1.getId()); + assertThat(client0.isReclaimed()).isTrue(); + } + + @Test public void releaseFrontendTest_UnderTheSameExclusiveGroup() throws RemoteException { // Register clients TunerClient client0 = new TunerClient(); @@ -565,6 +615,74 @@ public class TunerResourceManagerServiceTest { } @Test + @EnableFlags({FLAG_SET_RESOURCE_HOLDER_RETAIN}) + public void requestCasTest_NoCasAvailable_RequestWithEqualPriority() throws RemoteException { + // Register clients + TunerClient client0 = new TunerClient(); + TunerClient client1 = new TunerClient(); + client0.register( + "0" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + client1.register( + "1" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + + // Init cas resources. + mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/); + + CasSessionRequest request = casSessionRequest(client0.getId(), 1 /*casSystemId*/); + long[] casSessionHandle = new long[1]; + + // client0 requests for 2 cas sessions. + assertThat( + mTunerResourceManagerService.requestCasSessionInternal(request, casSessionHandle)) + .isTrue(); + assertThat( + mTunerResourceManagerService.requestCasSessionInternal(request, casSessionHandle)) + .isTrue(); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0])) + .isEqualTo(1); + assertThat(client0.getProfile().getInUseCasSystemId()).isEqualTo(1); + assertThat(mTunerResourceManagerService.getCasResource(1).getOwnerClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList(client0.getId()))); + assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isTrue(); + + // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder + // to maintain ownership such as requester (client1) will not get the resources. + client1.getProfile().setResourceHolderRetain(true); + + request = casSessionRequest(client1.getId(), 1); + assertThat( + mTunerResourceManagerService.requestCasSessionInternal(request, casSessionHandle)) + .isFalse(); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0])) + .isEqualTo(-1); + assertThat(client0.getProfile().getInUseCasSystemId()).isEqualTo(1); + assertThat(client1.getProfile().getInUseCasSystemId()) + .isEqualTo(ClientProfile.INVALID_RESOURCE_ID); + assertThat(mTunerResourceManagerService.getCasResource(1).getOwnerClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList(client0.getId()))); + assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isTrue(); + assertThat(client0.isReclaimed()).isFalse(); + + // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource + // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the + // resources. + client1.getProfile().setResourceHolderRetain(false); + + assertThat( + mTunerResourceManagerService.requestCasSessionInternal(request, casSessionHandle)) + .isTrue(); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(casSessionHandle[0])) + .isEqualTo(1); + assertThat(client0.getProfile().getInUseCasSystemId()) + .isEqualTo(ClientProfile.INVALID_RESOURCE_ID); + assertThat(client1.getProfile().getInUseCasSystemId()).isEqualTo(1); + assertThat(mTunerResourceManagerService.getCasResource(1).getOwnerClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList(client1.getId()))); + assertThat(mTunerResourceManagerService.getCasResource(1).isFullyUsed()).isFalse(); + assertThat(client0.isReclaimed()).isTrue(); + } + + @Test public void requestCiCamTest_NoCiCamAvailable_RequestWithHigherPriority() throws RemoteException { // Register clients @@ -612,6 +730,71 @@ public class TunerResourceManagerServiceTest { } @Test + @EnableFlags({FLAG_SET_RESOURCE_HOLDER_RETAIN}) + public void requestCiCamTest_NoCiCamAvailable_RequestWithEqualPriority() + throws RemoteException { + // Register clients + TunerClient client0 = new TunerClient(); + TunerClient client1 = new TunerClient(); + client0.register( + "0" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + client1.register( + "1" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + + // Init cicam/cas resources. + mTunerResourceManagerService.updateCasInfoInternal(1 /*casSystemId*/, 2 /*maxSessionNum*/); + + TunerCiCamRequest request = tunerCiCamRequest(client0.getId(), 1 /*ciCamId*/); + long[] ciCamHandle = new long[1]; + + // client0 request for 2 ciCam sessions. + assertThat(mTunerResourceManagerService.requestCiCamInternal(request, ciCamHandle)) + .isTrue(); + assertThat(mTunerResourceManagerService.requestCiCamInternal(request, ciCamHandle)) + .isTrue(); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(ciCamHandle[0])) + .isEqualTo(1); + assertThat(client0.getProfile().getInUseCiCamId()).isEqualTo(1); + assertThat(mTunerResourceManagerService.getCiCamResource(1).getOwnerClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList(client0.getId()))); + assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isTrue(); + + // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder + // (client0) to maintain ownership such as requester will not get the resources. + client1.getProfile().setResourceHolderRetain(true); + + request = tunerCiCamRequest(client1.getId(), 1); + assertThat(mTunerResourceManagerService.requestCiCamInternal(request, ciCamHandle)) + .isFalse(); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(ciCamHandle[0])) + .isEqualTo(-1); + assertThat(client0.getProfile().getInUseCiCamId()).isEqualTo(1); + assertThat(client1.getProfile().getInUseCiCamId()) + .isEqualTo(ClientProfile.INVALID_RESOURCE_ID); + assertThat(mTunerResourceManagerService.getCiCamResource(1).getOwnerClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList(client0.getId()))); + assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isTrue(); + assertThat(client0.isReclaimed()).isFalse(); + + // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource + // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the + // resources. + client1.getProfile().setResourceHolderRetain(false); + + assertThat(mTunerResourceManagerService.requestCiCamInternal(request, ciCamHandle)) + .isTrue(); + assertThat(mTunerResourceManagerService.getResourceIdFromHandle(ciCamHandle[0])) + .isEqualTo(1); + assertThat(client0.getProfile().getInUseCiCamId()) + .isEqualTo(ClientProfile.INVALID_RESOURCE_ID); + assertThat(client1.getProfile().getInUseCiCamId()).isEqualTo(1); + assertThat(mTunerResourceManagerService.getCiCamResource(1).getOwnerClientIds()) + .isEqualTo(new HashSet<Integer>(Arrays.asList(client1.getId()))); + assertThat(mTunerResourceManagerService.getCiCamResource(1).isFullyUsed()).isFalse(); + assertThat(client0.isReclaimed()).isTrue(); + } + + @Test public void releaseCasTest() throws RemoteException { // Register clients TunerClient client0 = new TunerClient(); @@ -721,6 +904,59 @@ public class TunerResourceManagerServiceTest { } @Test + @EnableFlags({FLAG_SET_RESOURCE_HOLDER_RETAIN}) + public void requestLnbTest_NoLnbAvailable_RequestWithEqualPriority() throws RemoteException { + // Register clients + TunerClient client0 = new TunerClient(); + TunerClient client1 = new TunerClient(); + client0.register( + "0" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + client1.register( + "1" /*sessionId*/, TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 100); + + // Init lnb resources. + long[] lnbHandles = {1}; + mTunerResourceManagerService.setLnbInfoListInternal(lnbHandles); + + // client0 requests 1 lnb + TunerLnbRequest request = new TunerLnbRequest(); + request.clientId = client0.getId(); + long[] lnbHandle = new long[1]; + assertThat(mTunerResourceManagerService.requestLnbInternal(request, lnbHandle)).isTrue(); + assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]); + assertThat(client0.getProfile().getInUseLnbHandles()) + .isEqualTo(new HashSet<Long>(Arrays.asList(lnbHandles[0]))); + + // setResourceHolderRetain sets mResourceHolderRetain to true to allow the Resource Holder + // (client0) to maintain ownership such as requester will not get the resources. + client1.getProfile().setResourceHolderRetain(true); + + request = new TunerLnbRequest(); + request.clientId = client1.getId(); + + assertThat(mTunerResourceManagerService.requestLnbInternal(request, lnbHandle)).isFalse(); + assertThat(lnbHandle[0]).isNotEqualTo(lnbHandles[0]); + assertThat(mTunerResourceManagerService.getLnbResource(lnbHandles[0]).isInUse()).isTrue(); + assertThat(mTunerResourceManagerService.getLnbResource(lnbHandles[0]).getOwnerClientId()) + .isEqualTo(client0.getId()); + assertThat(client0.isReclaimed()).isFalse(); + assertThat(client1.getProfile().getInUseLnbHandles().size()).isEqualTo(0); + + // setResourceHolderRetain sets mResourceHolderRetain to false to allow the Resource + // Challenger (client1) to acquire the resource and Resource Holder loses ownership of the + // resources. + client1.getProfile().setResourceHolderRetain(false); + + assertThat(mTunerResourceManagerService.requestLnbInternal(request, lnbHandle)).isTrue(); + assertThat(lnbHandle[0]).isEqualTo(lnbHandles[0]); + assertThat(mTunerResourceManagerService.getLnbResource(lnbHandles[0]).isInUse()).isTrue(); + assertThat(mTunerResourceManagerService.getLnbResource(lnbHandles[0]).getOwnerClientId()) + .isEqualTo(client1.getId()); + assertThat(client0.isReclaimed()).isTrue(); + assertThat(client0.getProfile().getInUseLnbHandles().size()).isEqualTo(0); + } + + @Test public void releaseLnbTest() throws RemoteException { // Register clients TunerClient client0 = new TunerClient(); |