Loading services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +62 −13 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ import com.android.internal.annotations.GuardedBy; import java.util.Collection; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; /** * A class that represents a broker for the endpoint registered by the client app. This class Loading Loading @@ -89,8 +88,11 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /** The remote callback interface for this endpoint. */ private final IContextHubEndpointCallback mContextHubEndpointCallback; /** True if this endpoint is registered with the service. */ private AtomicBoolean mIsRegistered = new AtomicBoolean(true); /** True if this endpoint is registered with the service/HAL. */ @GuardedBy("mRegistrationLock") private boolean mIsRegistered = false; private final Object mRegistrationLock = new Object(); private final Object mOpenSessionLock = new Object(); Loading Loading @@ -192,7 +194,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub public int openSession(HubEndpointInfo destination, String serviceDescriptor) throws RemoteException { super.openSession_enforcePermission(); if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered"); if (!isRegistered()) throw new IllegalStateException("Endpoint is not registered"); if (!hasEndpointPermissions(destination)) { throw new SecurityException( "Insufficient permission to open a session with endpoint: " + destination); Loading Loading @@ -223,7 +225,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void closeSession(int sessionId, int reason) throws RemoteException { super.closeSession_enforcePermission(); if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered"); if (!isRegistered()) throw new IllegalStateException("Endpoint is not registered"); if (!cleanupSessionResources(sessionId)) { throw new IllegalArgumentException( "Unknown session ID in closeSession: id=" + sessionId); Loading @@ -235,19 +237,26 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregister() { super.unregister_enforcePermission(); mIsRegistered.set(false); try { mHubInterface.unregisterEndpoint(mHalEndpointInfo); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e); } synchronized (mOpenSessionLock) { // Iterate in reverse since cleanupSessionResources will remove the entry for (int i = mSessionInfoMap.size() - 1; i >= 0; i--) { int id = mSessionInfoMap.keyAt(i); halCloseEndpointSessionNoThrow(id, Reason.ENDPOINT_GONE); cleanupSessionResources(id); } } synchronized (mRegistrationLock) { if (!isRegistered()) { Log.w(TAG, "Attempting to unregister when already unregistered"); return; } mIsRegistered = false; try { mHubInterface.unregisterEndpoint(mHalEndpointInfo); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e); } } mEndpointManager.unregisterEndpoint(mEndpointInfo.getIdentifier().getEndpoint()); releaseWakeLockOnExit(); } Loading Loading @@ -335,7 +344,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /** Invoked when the underlying binder of this broker has died at the client process. */ @Override public void binderDied() { if (mIsRegistered.get()) { if (isRegistered()) { unregister(); } } Loading Loading @@ -365,6 +374,22 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } /** * Registers this endpoints with the Context Hub HAL. * * @throws RemoteException if the registrations fails with a RemoteException */ /* package */ void register() throws RemoteException { synchronized (mRegistrationLock) { if (isRegistered()) { Log.w(TAG, "Attempting to register when already registered"); } else { mHubInterface.registerEndpoint(mHalEndpointInfo); mIsRegistered = true; } } } /* package */ void attachDeathRecipient() throws RemoteException { if (mContextHubEndpointCallback != null) { mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */); Loading Loading @@ -425,6 +450,24 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } /* package */ void onHalRestart() { synchronized (mRegistrationLock) { mIsRegistered = false; try { register(); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL registerEndpoint", e); } } synchronized (mOpenSessionLock) { for (int i = mSessionInfoMap.size() - 1; i >= 0; i--) { int id = mSessionInfoMap.keyAt(i); onCloseEndpointSession(id, Reason.HUB_RESET); } } // TODO(b/390029594): Cancel any ongoing reliable communication transactions } private Optional<Byte> onEndpointSessionOpenRequestInternal( int sessionId, HubEndpointInfo initiator, String serviceDescriptor) { if (!hasEndpointPermissions(initiator)) { Loading Loading @@ -553,7 +596,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub private void acquireWakeLock() { Binder.withCleanCallingIdentity( () -> { if (mIsRegistered.get()) { if (isRegistered()) { mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS); } }); Loading Loading @@ -608,4 +651,10 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } return true; } private boolean isRegistered() { synchronized (mRegistrationLock) { return mIsRegistered; } } } services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +9 −6 Original line number Diff line number Diff line Loading @@ -206,12 +206,6 @@ import java.util.function.Consumer; EndpointInfo halEndpointInfo = ContextHubServiceUtil.createHalEndpointInfo( pendingEndpointInfo, endpointId, SERVICE_HUB_ID); try { mHubInterface.registerEndpoint(halEndpointInfo); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL registerEndpoint", e); throw e; } broker = new ContextHubEndpointBroker( mContext, Loading @@ -222,6 +216,7 @@ import java.util.function.Consumer; packageName, attributionTag, mTransactionManager); broker.register(); mEndpointMap.put(endpointId, broker); try { Loading Loading @@ -282,6 +277,14 @@ import java.util.function.Consumer; mEndpointMap.remove(endpointId); } /** Invoked by the service when the Context Hub HAL restarts. */ /* package */ void onHalRestart() { for (ContextHubEndpointBroker broker : mEndpointMap.values()) { // The broker will close existing sessions and re-register itself broker.onHalRestart(); } } @Override public void onEndpointSessionOpenRequest( int sessionId, Loading services/core/java/com/android/server/location/contexthub/ContextHubService.java +3 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,9 @@ public class ContextHubService extends IContextHubService.Stub { if (mHubInfoRegistry != null) { mHubInfoRegistry.onHalRestart(); } if (mEndpointManager != null) { mEndpointManager.onHalRestart(); } resetSettings(); if (Flags.reconnectHostEndpointsAfterHalRestart()) { mClientManager.forEachClientOfHub(mContextHubId, Loading services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java +111 −17 Original line number Diff line number Diff line Loading @@ -20,10 +20,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.hardware.contexthub.EndpointInfo; import android.hardware.contexthub.ErrorCode; import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.HubEndpointInfo.HubEndpointIdentifier; Loading @@ -32,6 +34,7 @@ import android.hardware.contexthub.IContextHubEndpoint; import android.hardware.contexthub.IContextHubEndpointCallback; import android.hardware.contexthub.IEndpointCommunication; import android.hardware.contexthub.MessageDeliveryStatus; import android.hardware.contexthub.Reason; import android.os.Binder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; Loading Loading @@ -61,6 +64,9 @@ public class ContextHubEndpointTest { private static final int ENDPOINT_ID = 1; private static final String ENDPOINT_PACKAGE_NAME = "com.android.server.location.contexthub"; private static final String TARGET_ENDPOINT_NAME = "Example target endpoint"; private static final int TARGET_ENDPOINT_ID = 1; private ContextHubClientManager mClientManager; private ContextHubEndpointManager mEndpointManager; private HubInfoRegistry mHubInfoRegistry; Loading Loading @@ -95,23 +101,8 @@ public class ContextHubEndpointTest { @Test public void testRegisterEndpoint() throws RemoteException { // Register an endpoint and confirm we can get a valid IContextHubEndoint reference HubEndpointInfo info = new HubEndpointInfo( ENDPOINT_NAME, ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); IContextHubEndpoint endpoint = mEndpointManager.registerEndpoint( info, mMockCallback, ENDPOINT_PACKAGE_NAME, /* attributionTag= */ null); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(1); assertThat(endpoint).isNotNull(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); assertThat(assignedInfo).isNotNull(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); assertThat(assignedIdentifier).isNotNull(); // Unregister the endpoint and confirm proper clean-up mEndpointManager.unregisterEndpoint(assignedIdentifier.getEndpoint()); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(0); IContextHubEndpoint endpoint = registerExampleEndpoint(); unregisterExampleEndpoint(endpoint); } @Test Loading Loading @@ -146,4 +137,107 @@ public class ContextHubEndpointTest { assertThat(statusCaptor.getValue().messageSequenceNumber).isEqualTo(sequenceNumber); assertThat(statusCaptor.getValue().errorCode).isEqualTo(ErrorCode.DESTINATION_NOT_FOUND); } @Test public void testHalRestart() throws RemoteException { IContextHubEndpoint endpoint = registerExampleEndpoint(); // Verify that the endpoint is still registered after a HAL restart HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); mEndpointManager.onHalRestart(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications, times(2)).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); assertThat(statusCaptor.getValue().id.hubId).isEqualTo(assignedIdentifier.getHub()); unregisterExampleEndpoint(endpoint); } @Test public void testHalRestartOnOpenSession() throws RemoteException { assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); IContextHubEndpoint endpoint = registerExampleEndpoint(); HubEndpointInfo targetInfo = new HubEndpointInfo( TARGET_ENDPOINT_NAME, TARGET_ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); int sessionId = endpoint.openSession(targetInfo, /* serviceDescriptor= */ null); mEndpointManager.onEndpointSessionOpenComplete(sessionId); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE - 1); mEndpointManager.onHalRestart(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications, times(2)).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); assertThat(statusCaptor.getValue().id.hubId).isEqualTo(assignedIdentifier.getHub()); verify(mMockCallback) .onSessionClosed( sessionId, ContextHubServiceUtil.toAppHubEndpointReason(Reason.HUB_RESET)); unregisterExampleEndpoint(endpoint); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); } @Test public void testOpenSessionOnUnregistration() throws RemoteException { assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); IContextHubEndpoint endpoint = registerExampleEndpoint(); HubEndpointInfo targetInfo = new HubEndpointInfo( TARGET_ENDPOINT_NAME, TARGET_ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); int sessionId = endpoint.openSession(targetInfo, /* serviceDescriptor= */ null); mEndpointManager.onEndpointSessionOpenComplete(sessionId); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE - 1); unregisterExampleEndpoint(endpoint); verify(mMockEndpointCommunications).closeEndpointSession(sessionId, Reason.ENDPOINT_GONE); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); } private IContextHubEndpoint registerExampleEndpoint() throws RemoteException { HubEndpointInfo info = new HubEndpointInfo( ENDPOINT_NAME, ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); IContextHubEndpoint endpoint = mEndpointManager.registerEndpoint( info, mMockCallback, ENDPOINT_PACKAGE_NAME, /* attributionTag= */ null); assertThat(endpoint).isNotNull(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); assertThat(assignedInfo).isNotNull(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); assertThat(assignedIdentifier).isNotNull(); // Confirm registerEndpoint was called with the right contents ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); assertThat(statusCaptor.getValue().id.hubId).isEqualTo(assignedIdentifier.getHub()); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(1); return endpoint; } private void unregisterExampleEndpoint(IContextHubEndpoint endpoint) throws RemoteException { HubEndpointInfo expectedInfo = endpoint.getAssignedHubEndpointInfo(); endpoint.unregister(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications).unregisterEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id) .isEqualTo(expectedInfo.getIdentifier().getEndpoint()); assertThat(statusCaptor.getValue().id.hubId) .isEqualTo(expectedInfo.getIdentifier().getHub()); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(0); } } Loading
services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +62 −13 Original line number Diff line number Diff line Loading @@ -43,7 +43,6 @@ import com.android.internal.annotations.GuardedBy; import java.util.Collection; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; /** * A class that represents a broker for the endpoint registered by the client app. This class Loading Loading @@ -89,8 +88,11 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /** The remote callback interface for this endpoint. */ private final IContextHubEndpointCallback mContextHubEndpointCallback; /** True if this endpoint is registered with the service. */ private AtomicBoolean mIsRegistered = new AtomicBoolean(true); /** True if this endpoint is registered with the service/HAL. */ @GuardedBy("mRegistrationLock") private boolean mIsRegistered = false; private final Object mRegistrationLock = new Object(); private final Object mOpenSessionLock = new Object(); Loading Loading @@ -192,7 +194,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub public int openSession(HubEndpointInfo destination, String serviceDescriptor) throws RemoteException { super.openSession_enforcePermission(); if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered"); if (!isRegistered()) throw new IllegalStateException("Endpoint is not registered"); if (!hasEndpointPermissions(destination)) { throw new SecurityException( "Insufficient permission to open a session with endpoint: " + destination); Loading Loading @@ -223,7 +225,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void closeSession(int sessionId, int reason) throws RemoteException { super.closeSession_enforcePermission(); if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered"); if (!isRegistered()) throw new IllegalStateException("Endpoint is not registered"); if (!cleanupSessionResources(sessionId)) { throw new IllegalArgumentException( "Unknown session ID in closeSession: id=" + sessionId); Loading @@ -235,19 +237,26 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) public void unregister() { super.unregister_enforcePermission(); mIsRegistered.set(false); try { mHubInterface.unregisterEndpoint(mHalEndpointInfo); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e); } synchronized (mOpenSessionLock) { // Iterate in reverse since cleanupSessionResources will remove the entry for (int i = mSessionInfoMap.size() - 1; i >= 0; i--) { int id = mSessionInfoMap.keyAt(i); halCloseEndpointSessionNoThrow(id, Reason.ENDPOINT_GONE); cleanupSessionResources(id); } } synchronized (mRegistrationLock) { if (!isRegistered()) { Log.w(TAG, "Attempting to unregister when already unregistered"); return; } mIsRegistered = false; try { mHubInterface.unregisterEndpoint(mHalEndpointInfo); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e); } } mEndpointManager.unregisterEndpoint(mEndpointInfo.getIdentifier().getEndpoint()); releaseWakeLockOnExit(); } Loading Loading @@ -335,7 +344,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /** Invoked when the underlying binder of this broker has died at the client process. */ @Override public void binderDied() { if (mIsRegistered.get()) { if (isRegistered()) { unregister(); } } Loading Loading @@ -365,6 +374,22 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } /** * Registers this endpoints with the Context Hub HAL. * * @throws RemoteException if the registrations fails with a RemoteException */ /* package */ void register() throws RemoteException { synchronized (mRegistrationLock) { if (isRegistered()) { Log.w(TAG, "Attempting to register when already registered"); } else { mHubInterface.registerEndpoint(mHalEndpointInfo); mIsRegistered = true; } } } /* package */ void attachDeathRecipient() throws RemoteException { if (mContextHubEndpointCallback != null) { mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */); Loading Loading @@ -425,6 +450,24 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } /* package */ void onHalRestart() { synchronized (mRegistrationLock) { mIsRegistered = false; try { register(); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL registerEndpoint", e); } } synchronized (mOpenSessionLock) { for (int i = mSessionInfoMap.size() - 1; i >= 0; i--) { int id = mSessionInfoMap.keyAt(i); onCloseEndpointSession(id, Reason.HUB_RESET); } } // TODO(b/390029594): Cancel any ongoing reliable communication transactions } private Optional<Byte> onEndpointSessionOpenRequestInternal( int sessionId, HubEndpointInfo initiator, String serviceDescriptor) { if (!hasEndpointPermissions(initiator)) { Loading Loading @@ -553,7 +596,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub private void acquireWakeLock() { Binder.withCleanCallingIdentity( () -> { if (mIsRegistered.get()) { if (isRegistered()) { mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS); } }); Loading Loading @@ -608,4 +651,10 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } return true; } private boolean isRegistered() { synchronized (mRegistrationLock) { return mIsRegistered; } } }
services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +9 −6 Original line number Diff line number Diff line Loading @@ -206,12 +206,6 @@ import java.util.function.Consumer; EndpointInfo halEndpointInfo = ContextHubServiceUtil.createHalEndpointInfo( pendingEndpointInfo, endpointId, SERVICE_HUB_ID); try { mHubInterface.registerEndpoint(halEndpointInfo); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL registerEndpoint", e); throw e; } broker = new ContextHubEndpointBroker( mContext, Loading @@ -222,6 +216,7 @@ import java.util.function.Consumer; packageName, attributionTag, mTransactionManager); broker.register(); mEndpointMap.put(endpointId, broker); try { Loading Loading @@ -282,6 +277,14 @@ import java.util.function.Consumer; mEndpointMap.remove(endpointId); } /** Invoked by the service when the Context Hub HAL restarts. */ /* package */ void onHalRestart() { for (ContextHubEndpointBroker broker : mEndpointMap.values()) { // The broker will close existing sessions and re-register itself broker.onHalRestart(); } } @Override public void onEndpointSessionOpenRequest( int sessionId, Loading
services/core/java/com/android/server/location/contexthub/ContextHubService.java +3 −0 Original line number Diff line number Diff line Loading @@ -259,6 +259,9 @@ public class ContextHubService extends IContextHubService.Stub { if (mHubInfoRegistry != null) { mHubInfoRegistry.onHalRestart(); } if (mEndpointManager != null) { mEndpointManager.onHalRestart(); } resetSettings(); if (Flags.reconnectHostEndpointsAfterHalRestart()) { mClientManager.forEachClientOfHub(mContextHubId, Loading
services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java +111 −17 Original line number Diff line number Diff line Loading @@ -20,10 +20,12 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; import android.hardware.contexthub.EndpointInfo; import android.hardware.contexthub.ErrorCode; import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.HubEndpointInfo.HubEndpointIdentifier; Loading @@ -32,6 +34,7 @@ import android.hardware.contexthub.IContextHubEndpoint; import android.hardware.contexthub.IContextHubEndpointCallback; import android.hardware.contexthub.IEndpointCommunication; import android.hardware.contexthub.MessageDeliveryStatus; import android.hardware.contexthub.Reason; import android.os.Binder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; Loading Loading @@ -61,6 +64,9 @@ public class ContextHubEndpointTest { private static final int ENDPOINT_ID = 1; private static final String ENDPOINT_PACKAGE_NAME = "com.android.server.location.contexthub"; private static final String TARGET_ENDPOINT_NAME = "Example target endpoint"; private static final int TARGET_ENDPOINT_ID = 1; private ContextHubClientManager mClientManager; private ContextHubEndpointManager mEndpointManager; private HubInfoRegistry mHubInfoRegistry; Loading Loading @@ -95,23 +101,8 @@ public class ContextHubEndpointTest { @Test public void testRegisterEndpoint() throws RemoteException { // Register an endpoint and confirm we can get a valid IContextHubEndoint reference HubEndpointInfo info = new HubEndpointInfo( ENDPOINT_NAME, ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); IContextHubEndpoint endpoint = mEndpointManager.registerEndpoint( info, mMockCallback, ENDPOINT_PACKAGE_NAME, /* attributionTag= */ null); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(1); assertThat(endpoint).isNotNull(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); assertThat(assignedInfo).isNotNull(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); assertThat(assignedIdentifier).isNotNull(); // Unregister the endpoint and confirm proper clean-up mEndpointManager.unregisterEndpoint(assignedIdentifier.getEndpoint()); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(0); IContextHubEndpoint endpoint = registerExampleEndpoint(); unregisterExampleEndpoint(endpoint); } @Test Loading Loading @@ -146,4 +137,107 @@ public class ContextHubEndpointTest { assertThat(statusCaptor.getValue().messageSequenceNumber).isEqualTo(sequenceNumber); assertThat(statusCaptor.getValue().errorCode).isEqualTo(ErrorCode.DESTINATION_NOT_FOUND); } @Test public void testHalRestart() throws RemoteException { IContextHubEndpoint endpoint = registerExampleEndpoint(); // Verify that the endpoint is still registered after a HAL restart HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); mEndpointManager.onHalRestart(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications, times(2)).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); assertThat(statusCaptor.getValue().id.hubId).isEqualTo(assignedIdentifier.getHub()); unregisterExampleEndpoint(endpoint); } @Test public void testHalRestartOnOpenSession() throws RemoteException { assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); IContextHubEndpoint endpoint = registerExampleEndpoint(); HubEndpointInfo targetInfo = new HubEndpointInfo( TARGET_ENDPOINT_NAME, TARGET_ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); int sessionId = endpoint.openSession(targetInfo, /* serviceDescriptor= */ null); mEndpointManager.onEndpointSessionOpenComplete(sessionId); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE - 1); mEndpointManager.onHalRestart(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications, times(2)).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); assertThat(statusCaptor.getValue().id.hubId).isEqualTo(assignedIdentifier.getHub()); verify(mMockCallback) .onSessionClosed( sessionId, ContextHubServiceUtil.toAppHubEndpointReason(Reason.HUB_RESET)); unregisterExampleEndpoint(endpoint); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); } @Test public void testOpenSessionOnUnregistration() throws RemoteException { assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); IContextHubEndpoint endpoint = registerExampleEndpoint(); HubEndpointInfo targetInfo = new HubEndpointInfo( TARGET_ENDPOINT_NAME, TARGET_ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); int sessionId = endpoint.openSession(targetInfo, /* serviceDescriptor= */ null); mEndpointManager.onEndpointSessionOpenComplete(sessionId); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE - 1); unregisterExampleEndpoint(endpoint); verify(mMockEndpointCommunications).closeEndpointSession(sessionId, Reason.ENDPOINT_GONE); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); } private IContextHubEndpoint registerExampleEndpoint() throws RemoteException { HubEndpointInfo info = new HubEndpointInfo( ENDPOINT_NAME, ENDPOINT_ID, ENDPOINT_PACKAGE_NAME, Collections.emptyList()); IContextHubEndpoint endpoint = mEndpointManager.registerEndpoint( info, mMockCallback, ENDPOINT_PACKAGE_NAME, /* attributionTag= */ null); assertThat(endpoint).isNotNull(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); assertThat(assignedInfo).isNotNull(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); assertThat(assignedIdentifier).isNotNull(); // Confirm registerEndpoint was called with the right contents ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); assertThat(statusCaptor.getValue().id.hubId).isEqualTo(assignedIdentifier.getHub()); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(1); return endpoint; } private void unregisterExampleEndpoint(IContextHubEndpoint endpoint) throws RemoteException { HubEndpointInfo expectedInfo = endpoint.getAssignedHubEndpointInfo(); endpoint.unregister(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications).unregisterEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id) .isEqualTo(expectedInfo.getIdentifier().getEndpoint()); assertThat(statusCaptor.getValue().id.hubId) .isEqualTo(expectedInfo.getIdentifier().getHub()); assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(0); } }