diff options
5 files changed, 149 insertions, 37 deletions
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 07c565a729bb..4eff954f1ec8 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/ClientProfile.java @@ -15,6 +15,9 @@ */ package com.android.server.tv.tunerresourcemanager; +import java.util.ArrayList; +import java.util.List; + /** * A client profile object used by the Tuner Resource Manager to record the registered clients' * information. @@ -60,6 +63,11 @@ public final class ClientProfile { private int mNiceValue; /** + * List of the frontend ids that are used by the current client. + */ + private List<Integer> mUsingFrontendIds = new ArrayList<>(); + + /** * Optional arbitrary priority value given by the client. * * <p>This value can override the default priorotiy calculated from @@ -114,6 +122,30 @@ public final class ClientProfile { mNiceValue = niceValue; } + /** + * Set when the client starts to use a frontend. + * + * @param frontendId being used. + */ + public void useFrontend(int frontendId) { + mUsingFrontendIds.add(frontendId); + } + + public List<Integer> getInUseFrontendIds() { + return mUsingFrontendIds; + } + + /** + * Called when the client released a frontend. + * + * <p>This could happen when client resource reclaimed. + * + * @param frontendId being released. + */ + public void releaseFrontend(int frontendId) { + mUsingFrontendIds.remove(frontendId); + } + @Override public String toString() { return "ClientProfile[id=" + this.mId + ", tvInputSessionId=" + this.mTvInputSessionId 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 621f2b024e84..cb31a502ecfa 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -28,6 +28,7 @@ import android.media.tv.tunerresourcemanager.TunerFrontendInfo; import android.media.tv.tunerresourcemanager.TunerFrontendRequest; import android.media.tv.tunerresourcemanager.TunerLnbRequest; import android.media.tv.tunerresourcemanager.TunerResourceManager; +import android.os.Binder; import android.os.RemoteException; import android.util.Log; import android.util.Slog; @@ -54,7 +55,7 @@ public class TunerResourceManagerService extends SystemService { // Array of the registered client profiles @VisibleForTesting private SparseArray<ClientProfile> mClientProfiles = new SparseArray<>(); private int mNextUnusedClientId = 0; - private List<Integer> mReleasedClientId = new ArrayList<Integer>(); + private List<Integer> mRegisteredClientIds = new ArrayList<Integer>(); // Array of the current available frontend resources @VisibleForTesting @@ -98,8 +99,12 @@ public class TunerResourceManagerService extends SystemService { throw new RemoteException("ResourceClientProfile can't be null"); } - if (clientId == null || clientId.length != 1) { - throw new RemoteException("clientId must be a size 1 array!"); + if (clientId == null) { + throw new RemoteException("clientId can't be null!"); + } + + if (!mPriorityCongfig.isDefinedUseCase(profile.getUseCase())) { + throw new RemoteException("Use undefined client use case:" + profile.getUseCase()); } synchronized (mLock) { @@ -108,20 +113,20 @@ public class TunerResourceManagerService extends SystemService { } @Override - public void unregisterClientProfile(int clientId) { - if (DEBUG) { - Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")"); + public void unregisterClientProfile(int clientId) throws RemoteException { + enforceAccessPermission(); + synchronized (mLock) { + if (!checkClientExists(clientId)) { + Slog.e(TAG, "Unregistering non exists client:" + clientId); + return; + } + unregisterClientProfileInternal(clientId); } - - mClientProfiles.remove(clientId); - mListeners.remove(clientId); - mReleasedClientId.add(clientId); } @Override public boolean updateClientPriority(int clientId, int priority, int niceValue) { enforceAccessPermission(); - synchronized (mLock) { return updateClientPriorityInternal(clientId, priority, niceValue); } @@ -243,24 +248,38 @@ public class TunerResourceManagerService extends SystemService { return; } // TODO tell if the client already exists - if (mReleasedClientId.isEmpty()) { - clientId[0] = mNextUnusedClientId++; - } else { - clientId[0] = mReleasedClientId.get(0); - mReleasedClientId.remove(0); - } + clientId[0] = mNextUnusedClientId++; - int callingPid = mManager.getClientPid(profile.getTvInputSessionId()); + int pid = profile.getTvInputSessionId() == null + ? Binder.getCallingPid() /*callingPid*/ + : mManager.getClientPid(profile.getTvInputSessionId()); /*tvAppId*/ ClientProfile clientProfile = new ClientProfile.Builder(clientId[0]) .tvInputSessionId(profile.getTvInputSessionId()) .useCase(profile.getUseCase()) - .processId(callingPid) + .processId(pid) .build(); - clientProfile.setPriority(getClientPriority(profile.getUseCase(), callingPid)); + clientProfile.setPriority(getClientPriority(profile.getUseCase(), pid)); mClientProfiles.append(clientId[0], clientProfile); mListeners.append(clientId[0], listener); + mRegisteredClientIds.add(clientId[0]); + } + + @VisibleForTesting + protected void unregisterClientProfileInternal(int clientId) { + if (DEBUG) { + Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")"); + } + for (int id : getClientProfile(clientId).getInUseFrontendIds()) { + getFrontendResource(id).removeOwner(); + for (int groupMemberId : getFrontendResource(id).getExclusiveGroupMemberFeIds()) { + getFrontendResource(groupMemberId).removeOwner(); + } + } + mClientProfiles.remove(clientId); + mListeners.remove(clientId); + mRegisteredClientIds.remove(clientId); } @VisibleForTesting @@ -355,12 +374,11 @@ public class TunerResourceManagerService extends SystemService { } frontendId[0] = TunerResourceManager.INVALID_FRONTEND_ID; - ClientProfile requestClient = getClientProfile(request.getClientId()); - if (requestClient == null) { - Slog.e(TAG, "Request from unregistered client. Id: " + request.getClientId()); + if (!checkClientExists(request.getClientId())) { + Slog.e(TAG, "Request frontend from unregistered client:" + request.getClientId()); return false; } - + ClientProfile requestClient = getClientProfile(request.getClientId()); int grantingFrontendId = -1; int inUseLowestPriorityFrId = -1; // Priority max value is 1000 @@ -393,7 +411,7 @@ public class TunerResourceManagerService extends SystemService { // Grant frontend when there is unused resource. if (grantingFrontendId > -1) { frontendId[0] = grantingFrontendId; - updateFrontendResourcesOnNewGrant(frontendId[0], request.getClientId()); + updateFrontendClientMappingOnNewGrant(frontendId[0], request.getClientId()); return true; } @@ -402,7 +420,7 @@ public class TunerResourceManagerService extends SystemService { if (inUseLowestPriorityFrId > -1 && (requestClient.getPriority() > currentLowestPriority)) { frontendId[0] = inUseLowestPriorityFrId; reclaimFrontendResource(getFrontendResource(frontendId[0]).getOwnerClientId()); - updateFrontendResourcesOnNewGrant(frontendId[0], request.getClientId()); + updateFrontendClientMappingOnNewGrant(frontendId[0], request.getClientId()); return true; } @@ -410,20 +428,20 @@ public class TunerResourceManagerService extends SystemService { } @VisibleForTesting - protected int getClientPriority(int useCase, int callingPid) { + protected int getClientPriority(int useCase, int pid) { if (DEBUG) { Slog.d(TAG, "getClientPriority useCase=" + useCase - + ", calling Pid=" + callingPid + ")"); + + ", pid=" + pid + ")"); } - if (isForeground(callingPid)) { + if (isForeground(pid)) { return mPriorityCongfig.getForegroundPriority(useCase); } return mPriorityCongfig.getBackgroundPriority(useCase); } @VisibleForTesting - protected boolean isForeground(int callingPid) { + protected boolean isForeground(int pid) { // TODO: how to get fg/bg information from pid return true; } @@ -439,11 +457,14 @@ public class TunerResourceManagerService extends SystemService { } } - private void updateFrontendResourcesOnNewGrant(int grantingId, int ownerClientId) { + private void updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) { FrontendResource grantingFrontend = getFrontendResource(grantingId); + ClientProfile ownerProfile = getClientProfile(ownerClientId); grantingFrontend.setOwner(ownerClientId); + ownerProfile.useFrontend(grantingId); for (int exclusiveGroupMember : grantingFrontend.getExclusiveGroupMemberFeIds()) { getFrontendResource(exclusiveGroupMember).setOwner(ownerClientId); + ownerProfile.useFrontend(exclusiveGroupMember); } } @@ -475,6 +496,10 @@ public class TunerResourceManagerService extends SystemService { return mFrontendResources; } + private boolean checkClientExists(int clientId) { + return mRegisteredClientIds.contains(clientId); + } + private void enforceAccessPermission() { getContext().enforceCallingOrSelfPermission( "android.permission.TUNER_RESOURCE_ACCESS", TAG); diff --git a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java index e6d672d9acbc..8c2de475b99b 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/UseCasePriorityHints.java @@ -95,8 +95,10 @@ public class UseCasePriorityHints { } catch (XmlPullParserException e) { Slog.e(TAG, "Unable to parse vendor file: " + file, e); } - } else if (DEBUG) { - Slog.i(TAG, "no vendor priority configuration available. Using default priority"); + } else { + if (DEBUG) { + Slog.i(TAG, "no vendor priority configuration available. Using default priority"); + } addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND, 180, 100); addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_SCAN, 450, 200); addNewUseCasePriority(TvInputService.PRIORITY_HINT_USE_CASE_TYPE_PLAYBACK, 480, 300); 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 72fbaef339a3..192c6fe4ab75 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 @@ -452,4 +452,46 @@ public class TunerResourceManagerServiceTest { .get(infos[1].getId()).getOwnerClientId()).isEqualTo(clientId1[0]); assertThat(mReclaimingId).isEqualTo(clientId0[0]); } + + @Test + public void unregisterClientTest_usingFrontend() { + // Register client + 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[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[] frontendId = new int[1]; + try { + assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) + .isTrue(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + assertThat(frontendId[0]).isEqualTo(infos[0].getId()); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId()) + .isInUse()).isTrue(); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId()) + .isInUse()).isTrue(); + + // Unregister client when using frontend + mTunerResourceManagerService.unregisterClientProfileInternal(clientId[0]); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[0].getId()) + .isInUse()).isFalse(); + assertThat(mTunerResourceManagerService.getFrontendResources().get(infos[1].getId()) + .isInUse()).isFalse(); + + } } diff --git a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java index 8a75d5c2a380..ab5665ba99fc 100644 --- a/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java +++ b/services/tests/servicestests/src/com/android/server/tv/tunerresourcemanager/UseCasePriorityHintsTest.java @@ -58,17 +58,16 @@ public class UseCasePriorityHintsTest { @Before public void setUp() throws Exception { mPriorityHints = new UseCasePriorityHints(); - } - - @Test - public void parseTest_parseSampleXml() { try { mPriorityHints.parseInternal( new ByteArrayInputStream(mExampleXML.getBytes(StandardCharsets.UTF_8))); } catch (IOException | XmlPullParserException e) { Slog.e(TAG, "Error parse xml.", e); } + } + @Test + public void parseTest_parseSampleXml() { // Pre-defined foreground assertThat(mPriorityHints.getForegroundPriority( TvInputService.PRIORITY_HINT_USE_CASE_TYPE_BACKGROUND)).isEqualTo(180); @@ -97,4 +96,16 @@ public class UseCasePriorityHintsTest { assertThat(mPriorityHints.getForegroundPriority(1001)).isEqualTo(300); assertThat(mPriorityHints.getBackgroundPriority(1001)).isEqualTo(80); } + + @Test + public void isDefinedUseCaseTest_invalidUseCase() { + assertThat(mPriorityHints.isDefinedUseCase(1992)).isFalse(); + } + + @Test + public void isDefinedUseCaseTest_validUseCase() { + assertThat(mPriorityHints.isDefinedUseCase(1001)).isTrue(); + assertThat(mPriorityHints.isDefinedUseCase( + TvInputService.PRIORITY_HINT_USE_CASE_TYPE_RECORD)).isTrue(); + } } |