From 38ff0181c3ab1db077f160d9d940048ced73b81e Mon Sep 17 00:00:00 2001 From: Amy Date: Tue, 18 Feb 2020 21:12:04 -0800 Subject: [PATCH] Add requestFrontend implementation in TunerResourceManager Test: atest TunerResourceManagerServiceTest Bug: 147380513 Change-Id: Icec048913e2cbe141448c0c322d37c233588dfcd (cherry picked from commit 9d150f58bd4e1994c406c7f0034ce7b3c664eace) --- .../ResourceClientProfile.java | 3 +- .../TunerResourceManagerService.java | 278 +++++++++++++----- .../TunerResourceManagerServiceTest.java | 277 ++++++++++++++++- 3 files changed, 481 insertions(+), 77 deletions(-) diff --git a/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java index 68372444cb837..598ff8f3f0758 100644 --- a/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java +++ b/media/java/android/media/tv/tunerresourcemanager/ResourceClientProfile.java @@ -78,7 +78,8 @@ public final class ResourceClientProfile implements Parcelable { * {@link android.media.tv.TvInputService.PRIORITY_HINT_USE_CASE_TYPE_LIVE} * {@link android.media.tv.TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD}. * New [use case : priority value] pair can be defined in the manifest by the - * OEM. Any undefined use case would cause IllegalArgumentException. + * OEM. The id of the useCaseVendor should be passed through this parameter. Any + * undefined use case would cause IllegalArgumentException. */ public ResourceClientProfile(@NonNull String tvInputSessionId, int useCase) { 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 c91a9297eb17a..ede620257dc47 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -48,6 +48,9 @@ public class TunerResourceManagerService extends SystemService { private static final String TAG = "TunerResourceManagerService"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + public static final int INVALID_CLIENT_ID = -1; + private static final int MAX_CLIENT_PRIORITY = 1000; + // Array of the registered client profiles @VisibleForTesting private SparseArray mClientProfiles = new SparseArray<>(); private int mNextUnusedClientId = 0; @@ -56,7 +59,6 @@ public class TunerResourceManagerService extends SystemService { // Array of the current available frontend resources @VisibleForTesting private SparseArray mFrontendResources = new SparseArray<>(); - @VisibleForTesting private SparseArray mFrontendTypeMap = new SparseArray<>(); // Array of the current available frontend ids private List mAvailableFrontendIds = new ArrayList(); @@ -73,40 +75,34 @@ public class TunerResourceManagerService extends SystemService { @Override public void onStart() { - publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService()); + onStart(false /*isForTesting*/); + } + + @VisibleForTesting + protected void onStart(boolean isForTesting) { + if (!isForTesting) { + publishBinderService(Context.TV_TUNER_RESOURCE_MGR_SERVICE, new BinderService()); + } mManager = (TvInputManager) getContext().getSystemService(Context.TV_INPUT_SERVICE); } private final class BinderService extends ITunerResourceManager.Stub { @Override public void registerClientProfile(@NonNull ResourceClientProfile profile, - @NonNull IResourcesReclaimListener listener, @NonNull int[] clientId) { - if (DEBUG) { - Slog.d(TAG, "registerClientProfile(clientProfile=" + profile + ")"); + @NonNull IResourcesReclaimListener listener, @NonNull int[] clientId) + throws RemoteException { + enforceAccessPermission(); + if (profile == null) { + throw new RemoteException("ResourceClientProfile can't be null"); } - // TODO tell if the client already exists - if (mReleasedClientId.isEmpty()) { - clientId[0] = mNextUnusedClientId++; - } else { - clientId[0] = mReleasedClientId.get(0); - mReleasedClientId.remove(0); + if (clientId == null || clientId.length != 1) { + throw new RemoteException("clientId must be a size 1 array!"); } - if (mManager == null) { - Slog.e(TAG, "TvInputManager is null. Can't register client profile."); - return; + synchronized (mLock) { + registerClientProfileInternal(profile, listener, clientId); } - - int callingPid = mManager.getClientPid(profile.getTvInputSessionId()); - - ClientProfile clientProfile = new ClientProfile.Builder(clientId[0]) - .tvInputSessionId(profile.getTvInputSessionId()) - .useCase(profile.getUseCase()) - .processId(callingPid) - .build(); - mClientProfiles.append(clientId[0], clientProfile); - mListeners.append(clientId[0], listener); } @Override @@ -122,24 +118,11 @@ public class TunerResourceManagerService extends SystemService { @Override public boolean updateClientPriority(int clientId, int priority, int niceValue) { - if (DEBUG) { - Slog.d(TAG, - "updateClientPriority(clientId=" + clientId + ", priority=" + priority - + ", niceValue=" + niceValue + ")"); + enforceAccessPermission(); + + synchronized (mLock) { + return updateClientPriorityInternal(clientId, priority, niceValue); } - - ClientProfile profile = mClientProfiles.get(clientId); - if (profile == null) { - Slog.e(TAG, - "Can not find client profile with id " + clientId - + " when trying to update the client priority."); - return false; - } - - profile.setPriority(priority); - profile.setNiceValue(niceValue); - - return true; } @Override @@ -174,28 +157,17 @@ public class TunerResourceManagerService extends SystemService { @Override public boolean requestFrontend(@NonNull TunerFrontendRequest request, @NonNull int[] frontendId) throws RemoteException { - if (DEBUG) { - Slog.d(TAG, "requestFrontend(request=" + request + ")"); + enforceAccessPermission(); + if (frontendId == null) { + throw new RemoteException("frontendId can't be null"); } - - frontendId[0] = TunerResourceManager.INVALID_FRONTEND_ID; - - if (mClientProfiles.get(request.getClientId()) == null) { - Slog.e(TAG, "Request from unregistered client. Id: " + request.getClientId()); - return false; + synchronized (mLock) { + try { + return requestFrontendInternal(request, frontendId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } - - String sessionId = mClientProfiles.get(request.getClientId()).getTvInputSessionId(); - - if (DEBUG) { - Slog.d(TAG, "session Id:" + sessionId + ")"); - } - - if (DEBUG) { - Slog.d(TAG, "No available Frontend found."); - } - - return false; } @Override @@ -256,6 +228,61 @@ public class TunerResourceManagerService extends SystemService { } } + @VisibleForTesting + protected void registerClientProfileInternal(ResourceClientProfile profile, + IResourcesReclaimListener listener, int[] clientId) { + if (DEBUG) { + Slog.d(TAG, "registerClientProfile(clientProfile=" + profile + ")"); + } + + clientId[0] = INVALID_CLIENT_ID; + if (mManager == null) { + Slog.e(TAG, "TvInputManager is null. Can't register client profile."); + return; + } + // TODO tell if the client already exists + if (mReleasedClientId.isEmpty()) { + clientId[0] = mNextUnusedClientId++; + } else { + clientId[0] = mReleasedClientId.get(0); + mReleasedClientId.remove(0); + } + + int callingPid = mManager.getClientPid(profile.getTvInputSessionId()); + + ClientProfile clientProfile = new ClientProfile.Builder(clientId[0]) + .tvInputSessionId(profile.getTvInputSessionId()) + .useCase(profile.getUseCase()) + .processId(callingPid) + .build(); + clientProfile.setPriority(getClientPriority(profile.getUseCase(), callingPid)); + + mClientProfiles.append(clientId[0], clientProfile); + mListeners.append(clientId[0], listener); + } + + @VisibleForTesting + protected boolean updateClientPriorityInternal(int clientId, int priority, int niceValue) { + if (DEBUG) { + Slog.d(TAG, + "updateClientPriority(clientId=" + clientId + ", priority=" + priority + + ", niceValue=" + niceValue + ")"); + } + + ClientProfile profile = getClientProfile(clientId); + if (profile == null) { + Slog.e(TAG, + "Can not find client profile with id " + clientId + + " when trying to update the client priority."); + return false; + } + + profile.setPriority(priority); + profile.setNiceValue(niceValue); + + return true; + } + @VisibleForTesting protected void setFrontendInfoListInternal(TunerFrontendInfo[] infos) { if (DEBUG) { @@ -273,7 +300,7 @@ public class TunerResourceManagerService extends SystemService { // Update frontendResources sparse array and other mappings accordingly for (int i = 0; i < infos.length; i++) { - if (mFrontendResources.get(infos[i].getId()) != null) { + if (getFrontendResource(infos[i].getId()) != null) { if (DEBUG) { Slog.d(TAG, "Frontend id=" + infos[i].getId() + "exists."); } @@ -286,12 +313,12 @@ public class TunerResourceManagerService extends SystemService { .build(); // Update the exclusive group member list in all the existing Frontend resource for (Integer feId : mAvailableFrontendIds) { - FrontendResource fe = mFrontendResources.get(feId.intValue()); + FrontendResource fe = getFrontendResource(feId.intValue()); if (fe.getExclusiveGroupId() == newFe.getExclusiveGroupId()) { newFe.addExclusiveGroupMemberFeId(fe.getId()); newFe.addExclusiveGroupMemberFeId(fe.getExclusiveGroupMemberFeIds()); for (Integer excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) { - mFrontendResources.get(excGroupmemberFeId.intValue()) + getFrontendResource(excGroupmemberFeId.intValue()) .addExclusiveGroupMemberFeId(newFe.getId()); } fe.addExclusiveGroupMemberFeId(newFe.getId()); @@ -307,20 +334,131 @@ public class TunerResourceManagerService extends SystemService { // TODO check if the removing resource is in use or not. Handle the conflict. for (Integer removingId : updatingFrontendIds) { // update the exclusive group id memver list - FrontendResource fe = mFrontendResources.get(removingId.intValue()); + FrontendResource fe = getFrontendResource(removingId.intValue()); fe.removeExclusiveGroupMemberFeId(new Integer(fe.getId())); for (Integer excGroupmemberFeId : fe.getExclusiveGroupMemberFeIds()) { - mFrontendResources.get(excGroupmemberFeId.intValue()) + getFrontendResource(excGroupmemberFeId.intValue()) .removeExclusiveGroupMemberFeId(new Integer(fe.getId())); } mFrontendResources.remove(removingId.intValue()); mAvailableFrontendIds.remove(removingId); } - for (int i = 0; i < mFrontendResources.size(); i++) { - int key = mFrontendResources.keyAt(i); - // get the object by the key. - FrontendResource r = mFrontendResources.get(key); + } + + @VisibleForTesting + protected boolean requestFrontendInternal(TunerFrontendRequest request, int[] frontendId) + throws RemoteException { + if (DEBUG) { + Slog.d(TAG, "requestFrontend(request=" + request + ")"); } + + frontendId[0] = TunerResourceManager.INVALID_FRONTEND_ID; + ClientProfile requestClient = getClientProfile(request.getClientId()); + if (requestClient == null) { + Slog.e(TAG, "Request from unregistered client. Id: " + request.getClientId()); + return false; + } + + int grantingFrontendId = -1; + int inUseLowestPriorityFrId = -1; + // Priority max value is 1000 + int currentLowestPriority = MAX_CLIENT_PRIORITY + 1; + for (int id : mAvailableFrontendIds) { + FrontendResource fr = getFrontendResource(id); + if (fr.getType() == request.getFrontendType()) { + if (!fr.isInUse()) { + // Grant unused frontend with no exclusive group members first. + if (fr.getExclusiveGroupMemberFeIds().size() == 0) { + grantingFrontendId = id; + break; + } else if (grantingFrontendId < 0) { + // Grant the unused frontend with lower id first if all the unused + // frontends have exclusive group members. + grantingFrontendId = id; + } + } else if (grantingFrontendId < 0) { + // Record the frontend id with the lowest client priority among all the + // in use frontends when no available frontend has been found. + int priority = getOwnerClientPriority(id); + if (currentLowestPriority > priority) { + inUseLowestPriorityFrId = id; + currentLowestPriority = priority; + } + } + } + } + + // Grant frontend when there is unused resource. + if (grantingFrontendId > -1) { + frontendId[0] = grantingFrontendId; + updateFrontendResourcesOnNewGrant(frontendId[0], request.getClientId()); + return true; + } + + // When all the resources are occupied, grant the lowest priority resource if the + // request client has higher priority. + if (inUseLowestPriorityFrId > -1 && (requestClient.getPriority() > currentLowestPriority)) { + frontendId[0] = inUseLowestPriorityFrId; + reclaimFrontendResource(getFrontendResource(frontendId[0]).getOwnerClientId()); + updateFrontendResourcesOnNewGrant(frontendId[0], request.getClientId()); + return true; + } + + return false; + } + + @VisibleForTesting + protected int getClientPriority(int useCase, int callingPid) { + // TODO: how to get fg/bg information from pid + if (DEBUG) { + Slog.d(TAG, "getClientPriority useCase=" + useCase + + ", calling Pid=" + callingPid + ")"); + } + + // TODO: get priority from the table built from the useCase config xml + return 0; + } + + @VisibleForTesting + protected void reclaimFrontendResource(int reclaimingId) throws RemoteException { + if (mListeners.get(reclaimingId) != null) { + try { + mListeners.get(reclaimingId).onReclaimResources(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + private void updateFrontendResourcesOnNewGrant(int grantingId, int ownerClientId) { + FrontendResource grantingFrontend = getFrontendResource(grantingId); + grantingFrontend.setOwner(ownerClientId); + for (int exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeIds()) { + getFrontendResource(exclusiveGroupMember).setOwner(ownerClientId); + } + } + + /** + * Get the owner client's priority from the frontend id. + * + * @param frontendId an in use frontend id. + * @return the priority of the owner client of the frontend. + */ + private int getOwnerClientPriority(int frontendId) { + return getClientProfile(getFrontendResource(frontendId).getOwnerClientId()).getPriority(); + } + + private ClientProfile getClientProfile(int clientId) { + return mClientProfiles.get(clientId); + } + + protected FrontendResource getFrontendResource(int frontendId) { + return mFrontendResources.get(frontendId); + } + + @VisibleForTesting + protected SparseArray getClientProfiles() { + return mClientProfiles; } @VisibleForTesting 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 02060ee03d86c..72fbaef339a38 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 @@ -18,11 +18,19 @@ package com.android.server.tv.tunerresourcemanager; import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; import android.content.Context; import android.content.ContextWrapper; +import android.media.tv.ITvInputManager; +import android.media.tv.TvInputManager; +import android.media.tv.TvInputService; import android.media.tv.tuner.frontend.FrontendSettings; +import android.media.tv.tunerresourcemanager.ResourceClientProfile; import android.media.tv.tunerresourcemanager.TunerFrontendInfo; +import android.media.tv.tunerresourcemanager.TunerFrontendRequest; +import android.media.tv.tunerresourcemanager.TunerResourceManager; +import android.os.RemoteException; import android.util.SparseArray; import androidx.test.InstrumentationRegistry; @@ -32,6 +40,7 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; @@ -45,13 +54,24 @@ import java.util.Arrays; public class TunerResourceManagerServiceTest { private static final String TAG = "TunerResourceManagerServiceTest"; private Context mContextSpy; + @Mock private ITvInputManager mITvInputManagerMock; private TunerResourceManagerService mTunerResourceManagerService; + private int mReclaimingId; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); + TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); - mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) {}; + when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager); + mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) { + @Override + protected void reclaimFrontendResource(int reclaimingId) { + mReclaimingId = reclaimingId; + } + }; + mTunerResourceManagerService.onStart(true /*isForTesting*/); + mReclaimingId = -1; } @Test @@ -85,9 +105,9 @@ public class TunerResourceManagerServiceTest { infos[1] = new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); infos[2] = - new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/); infos[3] = - new TunerFrontendInfo(3 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + new TunerFrontendInfo(3 /*id*/, FrontendSettings.TYPE_ATSC, 1 /*exclusiveGroupId*/); mTunerResourceManagerService.setFrontendInfoListInternal(infos); SparseArray resources = @@ -117,7 +137,7 @@ public class TunerResourceManagerServiceTest { infos[0] = new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); infos[1] = - new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/); mTunerResourceManagerService.setFrontendInfoListInternal(infos); SparseArray resources0 = @@ -139,7 +159,7 @@ public class TunerResourceManagerServiceTest { infos0[1] = new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); infos0[2] = - new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBT, 2 /*exclusiveGroupId*/); + new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 2 /*exclusiveGroupId*/); mTunerResourceManagerService.setFrontendInfoListInternal(infos0); TunerFrontendInfo[] infos1 = new TunerFrontendInfo[1]; @@ -168,7 +188,7 @@ public class TunerResourceManagerServiceTest { infos0[1] = new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); infos0[2] = - new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/); mTunerResourceManagerService.setFrontendInfoListInternal(infos0); TunerFrontendInfo[] infos1 = new TunerFrontendInfo[1]; @@ -187,4 +207,249 @@ public class TunerResourceManagerServiceTest { assertThat(fe.getExclusiveGroupMemberFeIds().size()).isEqualTo(0); } } + + @Test + public void requestFrontendTest_ClientNotRegistered() { + TunerFrontendRequest request = + new TunerFrontendRequest(0 /*clientId*/, FrontendSettings.TYPE_DVBT); + int[] frontendId = new int[1]; + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isFalse(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(TunerResourceManager.INVALID_FRONTEND_ID); + } + + @Test + public void requestFrontendTest_NoFrontendWithGiveTypeAvailable() { + ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + int[] clientId = new int[1]; + mTunerResourceManagerService.registerClientProfileInternal( + profile, null /*listener*/, clientId); + assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + + // Init frontend resources. + TunerFrontendInfo[] infos = new TunerFrontendInfo[1]; + infos[0] = + new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBS, 0 /*exclusiveGroupId*/); + mTunerResourceManagerService.setFrontendInfoListInternal(infos); + + TunerFrontendRequest request = + new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + int[] frontendId = new int[1]; + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isFalse(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(TunerResourceManager.INVALID_FRONTEND_ID); + } + + @Test + public void requestFrontendTest_FrontendWithNoExclusiveGroupAvailable() { + ResourceClientProfile profile = new ResourceClientProfile("0" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + int[] clientId = new int[1]; + mTunerResourceManagerService.registerClientProfileInternal( + profile, null /*listener*/, clientId); + assertThat(clientId[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + + // Init frontend resources. + TunerFrontendInfo[] infos = new TunerFrontendInfo[3]; + infos[0] = + new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/); + infos[1] = + new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + infos[2] = + new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/); + mTunerResourceManagerService.setFrontendInfoListInternal(infos); + + TunerFrontendRequest request = + new TunerFrontendRequest(clientId[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + int[] frontendId = new int[1]; + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(0); + } + + @Test + public void requestFrontendTest_FrontendWithExclusiveGroupAvailable() { + ResourceClientProfile profile0 = new ResourceClientProfile("0" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + ResourceClientProfile profile1 = new ResourceClientProfile("1" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + int[] clientId0 = new int[1]; + int[] clientId1 = new int[1]; + mTunerResourceManagerService.registerClientProfileInternal( + profile0, null /*listener*/, clientId0); + mTunerResourceManagerService.registerClientProfileInternal( + profile1, null /*listener*/, clientId1); + assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + + // Init frontend resources. + TunerFrontendInfo[] infos = new TunerFrontendInfo[3]; + infos[0] = + new TunerFrontendInfo(0 /*id*/, FrontendSettings.TYPE_DVBT, 0 /*exclusiveGroupId*/); + infos[1] = + new TunerFrontendInfo(1 /*id*/, FrontendSettings.TYPE_DVBT, 1 /*exclusiveGroupId*/); + infos[2] = + new TunerFrontendInfo(2 /*id*/, FrontendSettings.TYPE_DVBS, 1 /*exclusiveGroupId*/); + mTunerResourceManagerService.setFrontendInfoListInternal(infos); + + int[] frontendId = new int[1]; + TunerFrontendRequest request = + new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(infos[0].getId()); + + request = + new TunerFrontendRequest(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(infos[1].getId()); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId()) + .isInUse()).isTrue(); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[2].getId()) + .isInUse()).isTrue(); + } + + @Test + public void requestFrontendTest_NoFrontendAvailable_RequestWithLowerPriority() { + // Register clients + ResourceClientProfile[] profiles = new ResourceClientProfile[2]; + profiles[0] = new ResourceClientProfile("0" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + profiles[1] = new ResourceClientProfile("1" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + int[] clientPriorities = {100, 50}; + int[] clientId0 = new int[1]; + int[] clientId1 = new int[1]; + mTunerResourceManagerService.registerClientProfileInternal( + profiles[0], null /*listener*/, clientId0); + assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + mTunerResourceManagerService.getClientProfiles().get(clientId0[0]) + .setPriority(clientPriorities[0]); + mTunerResourceManagerService.registerClientProfileInternal( + profiles[1], null /*listener*/, clientId1); + assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + mTunerResourceManagerService.getClientProfiles().get(clientId1[0]) + .setPriority(clientPriorities[1]); + + // 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(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + int[] frontendId = new int[1]; + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + request = + new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isFalse(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(mReclaimingId).isEqualTo(-1); + + request = + new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS); + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isFalse(); + assertThat(mReclaimingId).isEqualTo(-1); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + @Test + public void requestFrontendTest_NoFrontendAvailable_RequestWithHigherPriority() { + // Register clients + ResourceClientProfile[] profiles = new ResourceClientProfile[2]; + profiles[0] = new ResourceClientProfile("0" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + profiles[1] = new ResourceClientProfile("1" /*sessionId*/, + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK); + int[] clientPriorities = {100, 500}; + int[] clientId0 = new int[1]; + int[] clientId1 = new int[1]; + mTunerResourceManagerService.registerClientProfileInternal( + profiles[0], null /*listener*/, clientId0); + assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + mTunerResourceManagerService.getClientProfiles().get(clientId0[0]) + .setPriority(clientPriorities[0]); + mTunerResourceManagerService.registerClientProfileInternal( + profiles[1], null /*listener*/, clientId1); + assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); + mTunerResourceManagerService.getClientProfiles().get(clientId1[0]) + .setPriority(clientPriorities[1]); + + // 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(clientId0[0] /*clientId*/, FrontendSettings.TYPE_DVBT); + int[] frontendId = new int[1]; + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(infos[0].getId()); + + request = + new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS); + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(infos[1].getId()); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId()) + .isInUse()).isTrue(); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId()) + .isInUse()).isTrue(); + assertThat(mTunerResourceManagerService.getFrontendResources() + .get(infos[0].getId()).getOwnerClientId()).isEqualTo(clientId1[0]); + assertThat(mTunerResourceManagerService.getFrontendResources() + .get(infos[1].getId()).getOwnerClientId()).isEqualTo(clientId1[0]); + assertThat(mReclaimingId).isEqualTo(clientId0[0]); + } }