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 df57492ace23b..04d551d0f84ec 100644 --- a/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java +++ b/services/core/java/com/android/server/tv/tunerresourcemanager/TunerResourceManagerService.java @@ -29,11 +29,12 @@ 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.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.Slog; -import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.server.SystemService; @@ -61,7 +62,8 @@ public class TunerResourceManagerService extends SystemService { // Map of the current available frontend resources private Map mFrontendResources = new HashMap<>(); - private SparseArray mListeners = new SparseArray<>(); + @GuardedBy("mLock") + private Map mListeners = new HashMap<>(); private TvInputManager mManager; private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints(); @@ -101,6 +103,10 @@ public class TunerResourceManagerService extends SystemService { throw new RemoteException("clientId can't be null!"); } + if (listener == null) { + throw new RemoteException("IResourcesReclaimListener can't be null!"); + } + if (!mPriorityCongfig.isDefinedUseCase(profile.getUseCase())) { throw new RemoteException("Use undefined client use case:" + profile.getUseCase()); } @@ -259,8 +265,7 @@ public class TunerResourceManagerService extends SystemService { .build(); clientProfile.setPriority(getClientPriority(profile.getUseCase(), pid)); - addClientProfile(clientId[0], clientProfile); - mListeners.append(clientId[0], listener); + addClientProfile(clientId[0], clientProfile, listener); } @VisibleForTesting @@ -269,7 +274,6 @@ public class TunerResourceManagerService extends SystemService { Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")"); } removeClientProfile(clientId); - mListeners.remove(clientId); } @VisibleForTesting @@ -392,6 +396,62 @@ public class TunerResourceManagerService extends SystemService { return false; } + @VisibleForTesting + protected class ResourcesReclaimListenerRecord implements IBinder.DeathRecipient { + private final IResourcesReclaimListener mListener; + private final int mClientId; + + public ResourcesReclaimListenerRecord(IResourcesReclaimListener listener, int clientId) { + mListener = listener; + mClientId = clientId; + } + + @Override + public void binderDied() { + synchronized (mLock) { + removeClientProfile(mClientId); + } + } + + public int getId() { + return mClientId; + } + + public IResourcesReclaimListener getListener() { + return mListener; + } + } + + private void addResourcesReclaimListener(int clientId, IResourcesReclaimListener listener) { + if (listener == null) { + if (DEBUG) { + Slog.w(TAG, "Listener is null when client " + clientId + " registered!"); + } + return; + } + + ResourcesReclaimListenerRecord record = + new ResourcesReclaimListenerRecord(listener, clientId); + + try { + listener.asBinder().linkToDeath(record, 0); + } catch (RemoteException e) { + Slog.w(TAG, "Listener already died."); + return; + } + + mListeners.put(clientId, record); + } + + @VisibleForTesting + protected void reclaimFrontendResource(int reclaimingId) { + try { + mListeners.get(reclaimingId).getListener().onReclaimResources(); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to reclaim resources on client " + reclaimingId, e); + } + } + @VisibleForTesting protected int getClientPriority(int useCase, int pid) { if (DEBUG) { @@ -411,17 +471,6 @@ public class TunerResourceManagerService extends SystemService { return true; } - @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 updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) { FrontendResource grantingFrontend = getFrontendResource(grantingId); ClientProfile ownerProfile = getClientProfile(ownerClientId); @@ -487,8 +536,10 @@ public class TunerResourceManagerService extends SystemService { return mClientProfiles.get(clientId); } - private void addClientProfile(int clientId, ClientProfile profile) { + private void addClientProfile(int clientId, ClientProfile profile, + IResourcesReclaimListener listener) { mClientProfiles.put(clientId, profile); + addResourcesReclaimListener(clientId, listener); } private void removeClientProfile(int clientId) { @@ -499,9 +550,11 @@ public class TunerResourceManagerService extends SystemService { } } mClientProfiles.remove(clientId); + mListeners.remove(clientId); } - private boolean checkClientExists(int clientId) { + @VisibleForTesting + protected boolean checkClientExists(int clientId) { return mClientProfiles.keySet().contains(clientId); } 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 08489f68c1c6d..8da3bdfdf38c3 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 @@ -26,12 +26,12 @@ 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.IResourcesReclaimListener; 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; import androidx.test.filters.SmallTest; @@ -45,9 +45,7 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.MockitoAnnotations; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.Map; /** @@ -60,7 +58,19 @@ public class TunerResourceManagerServiceTest { private Context mContextSpy; @Mock private ITvInputManager mITvInputManagerMock; private TunerResourceManagerService mTunerResourceManagerService; - private int mReclaimingId; + + private static final class TestResourcesReclaimListener extends IResourcesReclaimListener.Stub { + boolean mReclaimed; + + @Override + public void onReclaimResources() { + mReclaimed = true; + } + + public boolean isRelaimed() { + return mReclaimed; + } + } // A correspondence to compare a FrontendResource and a TunerFrontendInfo. private static final Correspondence FR_TFI_COMPARE = @@ -82,31 +92,14 @@ public class TunerResourceManagerServiceTest { } }; - private static List sparseArrayToList(SparseArray sparseArray) { - if (sparseArray == null) { - return null; - } - List arrayList = new ArrayList(sparseArray.size()); - for (int i = 0; i < sparseArray.size(); i++) { - arrayList.add(sparseArray.valueAt(i)); - } - return arrayList; - } - @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager); - mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) { - @Override - protected void reclaimFrontendResource(int reclaimingId) { - mReclaimingId = reclaimingId; - } - }; + mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy); mTunerResourceManagerService.onStart(true /*isForTesting*/); - mReclaimingId = -1; } @Test @@ -366,13 +359,15 @@ public class TunerResourceManagerServiceTest { int[] clientPriorities = {100, 50}; int[] clientId0 = new int[1]; int[] clientId1 = new int[1]; + TestResourcesReclaimListener listener = new TestResourcesReclaimListener(); + mTunerResourceManagerService.registerClientProfileInternal( - profiles[0], null /*listener*/, clientId0); + profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); mTunerResourceManagerService.getClientProfile(clientId0[0]) .setPriority(clientPriorities[0]); mTunerResourceManagerService.registerClientProfileInternal( - profiles[1], null /*listener*/, clientId1); + profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); mTunerResourceManagerService.getClientProfile(clientId1[0]) .setPriority(clientPriorities[1]); @@ -400,17 +395,17 @@ public class TunerResourceManagerServiceTest { try { assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) .isFalse(); + assertThat(listener.isRelaimed()).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); + assertThat(listener.isRelaimed()).isFalse(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -427,13 +422,14 @@ public class TunerResourceManagerServiceTest { int[] clientPriorities = {100, 500}; int[] clientId0 = new int[1]; int[] clientId1 = new int[1]; + TestResourcesReclaimListener listener = new TestResourcesReclaimListener(); mTunerResourceManagerService.registerClientProfileInternal( - profiles[0], null /*listener*/, clientId0); + profiles[0], listener, clientId0); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); mTunerResourceManagerService.getClientProfile(clientId0[0]) .setPriority(clientPriorities[0]); mTunerResourceManagerService.registerClientProfileInternal( - profiles[1], null /*listener*/, clientId1); + profiles[1], new TestResourcesReclaimListener(), clientId1); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); mTunerResourceManagerService.getClientProfile(clientId1[0]) .setPriority(clientPriorities[1]); @@ -474,7 +470,7 @@ public class TunerResourceManagerServiceTest { .getOwnerClientId()).isEqualTo(clientId1[0]); assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) .getOwnerClientId()).isEqualTo(clientId1[0]); - assertThat(mReclaimingId).isEqualTo(clientId0[0]); + assertThat(listener.isRelaimed()).isTrue(); } @Test @@ -516,6 +512,7 @@ public class TunerResourceManagerServiceTest { .isInUse()).isFalse(); assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) .isInUse()).isFalse(); + assertThat(mTunerResourceManagerService.checkClientExists(clientId[0])).isFalse(); } }