Merge "Handle binderDied on the resource reclaim listeners in TRM" into rvc-dev

This commit is contained in:
Amy Zhang
2020-03-07 01:41:09 +00:00
committed by Android (Google) Code Review
2 changed files with 97 additions and 47 deletions

View File

@@ -29,11 +29,12 @@ import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerLnbRequest; import android.media.tv.tunerresourcemanager.TunerLnbRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.Binder; import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.server.SystemService; import com.android.server.SystemService;
@@ -61,7 +62,8 @@ public class TunerResourceManagerService extends SystemService {
// Map of the current available frontend resources // Map of the current available frontend resources
private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>(); private Map<Integer, FrontendResource> mFrontendResources = new HashMap<>();
private SparseArray<IResourcesReclaimListener> mListeners = new SparseArray<>(); @GuardedBy("mLock")
private Map<Integer, ResourcesReclaimListenerRecord> mListeners = new HashMap<>();
private TvInputManager mManager; private TvInputManager mManager;
private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints(); private UseCasePriorityHints mPriorityCongfig = new UseCasePriorityHints();
@@ -101,6 +103,10 @@ public class TunerResourceManagerService extends SystemService {
throw new RemoteException("clientId can't be null!"); throw new RemoteException("clientId can't be null!");
} }
if (listener == null) {
throw new RemoteException("IResourcesReclaimListener can't be null!");
}
if (!mPriorityCongfig.isDefinedUseCase(profile.getUseCase())) { if (!mPriorityCongfig.isDefinedUseCase(profile.getUseCase())) {
throw new RemoteException("Use undefined client use case:" + profile.getUseCase()); throw new RemoteException("Use undefined client use case:" + profile.getUseCase());
} }
@@ -259,8 +265,7 @@ public class TunerResourceManagerService extends SystemService {
.build(); .build();
clientProfile.setPriority(getClientPriority(profile.getUseCase(), pid)); clientProfile.setPriority(getClientPriority(profile.getUseCase(), pid));
addClientProfile(clientId[0], clientProfile); addClientProfile(clientId[0], clientProfile, listener);
mListeners.append(clientId[0], listener);
} }
@VisibleForTesting @VisibleForTesting
@@ -269,7 +274,6 @@ public class TunerResourceManagerService extends SystemService {
Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")"); Slog.d(TAG, "unregisterClientProfile(clientId=" + clientId + ")");
} }
removeClientProfile(clientId); removeClientProfile(clientId);
mListeners.remove(clientId);
} }
@VisibleForTesting @VisibleForTesting
@@ -392,6 +396,62 @@ public class TunerResourceManagerService extends SystemService {
return false; 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 @VisibleForTesting
protected int getClientPriority(int useCase, int pid) { protected int getClientPriority(int useCase, int pid) {
if (DEBUG) { if (DEBUG) {
@@ -411,17 +471,6 @@ public class TunerResourceManagerService extends SystemService {
return true; 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) { private void updateFrontendClientMappingOnNewGrant(int grantingId, int ownerClientId) {
FrontendResource grantingFrontend = getFrontendResource(grantingId); FrontendResource grantingFrontend = getFrontendResource(grantingId);
ClientProfile ownerProfile = getClientProfile(ownerClientId); ClientProfile ownerProfile = getClientProfile(ownerClientId);
@@ -487,8 +536,10 @@ public class TunerResourceManagerService extends SystemService {
return mClientProfiles.get(clientId); return mClientProfiles.get(clientId);
} }
private void addClientProfile(int clientId, ClientProfile profile) { private void addClientProfile(int clientId, ClientProfile profile,
IResourcesReclaimListener listener) {
mClientProfiles.put(clientId, profile); mClientProfiles.put(clientId, profile);
addResourcesReclaimListener(clientId, listener);
} }
private void removeClientProfile(int clientId) { private void removeClientProfile(int clientId) {
@@ -499,9 +550,11 @@ public class TunerResourceManagerService extends SystemService {
} }
} }
mClientProfiles.remove(clientId); mClientProfiles.remove(clientId);
mListeners.remove(clientId);
} }
private boolean checkClientExists(int clientId) { @VisibleForTesting
protected boolean checkClientExists(int clientId) {
return mClientProfiles.keySet().contains(clientId); return mClientProfiles.keySet().contains(clientId);
} }

View File

@@ -26,12 +26,12 @@ import android.media.tv.ITvInputManager;
import android.media.tv.TvInputManager; import android.media.tv.TvInputManager;
import android.media.tv.TvInputService; import android.media.tv.TvInputService;
import android.media.tv.tuner.frontend.FrontendSettings; import android.media.tv.tuner.frontend.FrontendSettings;
import android.media.tv.tunerresourcemanager.IResourcesReclaimListener;
import android.media.tv.tunerresourcemanager.ResourceClientProfile; import android.media.tv.tunerresourcemanager.ResourceClientProfile;
import android.media.tv.tunerresourcemanager.TunerFrontendInfo; import android.media.tv.tunerresourcemanager.TunerFrontendInfo;
import android.media.tv.tunerresourcemanager.TunerFrontendRequest; import android.media.tv.tunerresourcemanager.TunerFrontendRequest;
import android.media.tv.tunerresourcemanager.TunerResourceManager; import android.media.tv.tunerresourcemanager.TunerResourceManager;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.SparseArray;
import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest; import androidx.test.filters.SmallTest;
@@ -45,9 +45,7 @@ import org.junit.runners.JUnit4;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import java.util.Map; import java.util.Map;
/** /**
@@ -60,7 +58,19 @@ public class TunerResourceManagerServiceTest {
private Context mContextSpy; private Context mContextSpy;
@Mock private ITvInputManager mITvInputManagerMock; @Mock private ITvInputManager mITvInputManagerMock;
private TunerResourceManagerService mTunerResourceManagerService; 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. // A correspondence to compare a FrontendResource and a TunerFrontendInfo.
private static final Correspondence<FrontendResource, TunerFrontendInfo> FR_TFI_COMPARE = private static final Correspondence<FrontendResource, TunerFrontendInfo> FR_TFI_COMPARE =
@@ -82,31 +92,14 @@ public class TunerResourceManagerServiceTest {
} }
}; };
private static <T> List<T> sparseArrayToList(SparseArray<T> sparseArray) {
if (sparseArray == null) {
return null;
}
List<T> arrayList = new ArrayList<T>(sparseArray.size());
for (int i = 0; i < sparseArray.size(); i++) {
arrayList.add(sparseArray.valueAt(i));
}
return arrayList;
}
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0); TvInputManager tvInputManager = new TvInputManager(mITvInputManagerMock, 0);
mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext())); mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getTargetContext()));
when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager); when(mContextSpy.getSystemService(Context.TV_INPUT_SERVICE)).thenReturn(tvInputManager);
mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy) { mTunerResourceManagerService = new TunerResourceManagerService(mContextSpy);
@Override
protected void reclaimFrontendResource(int reclaimingId) {
mReclaimingId = reclaimingId;
}
};
mTunerResourceManagerService.onStart(true /*isForTesting*/); mTunerResourceManagerService.onStart(true /*isForTesting*/);
mReclaimingId = -1;
} }
@Test @Test
@@ -366,13 +359,15 @@ public class TunerResourceManagerServiceTest {
int[] clientPriorities = {100, 50}; int[] clientPriorities = {100, 50};
int[] clientId0 = new int[1]; int[] clientId0 = new int[1];
int[] clientId1 = new int[1]; int[] clientId1 = new int[1];
TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
mTunerResourceManagerService.registerClientProfileInternal( mTunerResourceManagerService.registerClientProfileInternal(
profiles[0], null /*listener*/, clientId0); profiles[0], listener, clientId0);
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
mTunerResourceManagerService.getClientProfile(clientId0[0]) mTunerResourceManagerService.getClientProfile(clientId0[0])
.setPriority(clientPriorities[0]); .setPriority(clientPriorities[0]);
mTunerResourceManagerService.registerClientProfileInternal( mTunerResourceManagerService.registerClientProfileInternal(
profiles[1], null /*listener*/, clientId1); profiles[1], new TestResourcesReclaimListener(), clientId1);
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
mTunerResourceManagerService.getClientProfile(clientId1[0]) mTunerResourceManagerService.getClientProfile(clientId1[0])
.setPriority(clientPriorities[1]); .setPriority(clientPriorities[1]);
@@ -400,17 +395,17 @@ public class TunerResourceManagerServiceTest {
try { try {
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
.isFalse(); .isFalse();
assertThat(listener.isRelaimed()).isFalse();
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
assertThat(mReclaimingId).isEqualTo(-1);
request = request =
new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS); new TunerFrontendRequest(clientId1[0] /*clientId*/, FrontendSettings.TYPE_DVBS);
try { try {
assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId)) assertThat(mTunerResourceManagerService.requestFrontendInternal(request, frontendId))
.isFalse(); .isFalse();
assertThat(mReclaimingId).isEqualTo(-1); assertThat(listener.isRelaimed()).isFalse();
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }
@@ -427,13 +422,14 @@ public class TunerResourceManagerServiceTest {
int[] clientPriorities = {100, 500}; int[] clientPriorities = {100, 500};
int[] clientId0 = new int[1]; int[] clientId0 = new int[1];
int[] clientId1 = new int[1]; int[] clientId1 = new int[1];
TestResourcesReclaimListener listener = new TestResourcesReclaimListener();
mTunerResourceManagerService.registerClientProfileInternal( mTunerResourceManagerService.registerClientProfileInternal(
profiles[0], null /*listener*/, clientId0); profiles[0], listener, clientId0);
assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); assertThat(clientId0[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
mTunerResourceManagerService.getClientProfile(clientId0[0]) mTunerResourceManagerService.getClientProfile(clientId0[0])
.setPriority(clientPriorities[0]); .setPriority(clientPriorities[0]);
mTunerResourceManagerService.registerClientProfileInternal( mTunerResourceManagerService.registerClientProfileInternal(
profiles[1], null /*listener*/, clientId1); profiles[1], new TestResourcesReclaimListener(), clientId1);
assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID); assertThat(clientId1[0]).isNotEqualTo(TunerResourceManagerService.INVALID_CLIENT_ID);
mTunerResourceManagerService.getClientProfile(clientId1[0]) mTunerResourceManagerService.getClientProfile(clientId1[0])
.setPriority(clientPriorities[1]); .setPriority(clientPriorities[1]);
@@ -474,7 +470,7 @@ public class TunerResourceManagerServiceTest {
.getOwnerClientId()).isEqualTo(clientId1[0]); .getOwnerClientId()).isEqualTo(clientId1[0]);
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
.getOwnerClientId()).isEqualTo(clientId1[0]); .getOwnerClientId()).isEqualTo(clientId1[0]);
assertThat(mReclaimingId).isEqualTo(clientId0[0]); assertThat(listener.isRelaimed()).isTrue();
} }
@Test @Test
@@ -516,6 +512,7 @@ public class TunerResourceManagerServiceTest {
.isInUse()).isFalse(); .isInUse()).isFalse();
assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId()) assertThat(mTunerResourceManagerService.getFrontendResource(infos[1].getId())
.isInUse()).isFalse(); .isInUse()).isFalse();
assertThat(mTunerResourceManagerService.checkClientExists(clientId[0])).isFalse();
} }
} }