Loading services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +51 −25 Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; /** Loading Loading @@ -92,7 +94,8 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub private final ScheduledExecutorService mSessionTimeoutExecutor; /** The proxy to talk to the Context Hub HAL for endpoint communication. */ private final IEndpointCommunication mHubInterface; @GuardedBy("mRegistrationLock") private IEndpointCommunication mHubInterface; /** The manager that registered this endpoint. */ private final ContextHubEndpointManager mEndpointManager; Loading Loading @@ -257,7 +260,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /* package */ ContextHubEndpointBroker( Context context, IEndpointCommunication hubInterface, @NonNull IEndpointCommunication hubInterface, ContextHubEndpointManager endpointManager, EndpointInfo halEndpointInfo, @NonNull IContextHubEndpointCallback callback, Loading Loading @@ -311,8 +314,12 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub synchronized (mOpenSessionLock) { try { mSessionMap.put(sessionId, new Session(destination, false)); mHubInterface.openEndpointSession( sessionId, halEndpointInfo.id, mHalEndpointInfo.id, serviceDescriptor); getHubInterface() .openEndpointSession( sessionId, halEndpointInfo.id, mHalEndpointInfo.id, serviceDescriptor); } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) { Log.e(TAG, "Exception while calling HAL openEndpointSession", e); cleanupSessionResources(sessionId); Loading Loading @@ -350,7 +357,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } synchronized (mRegistrationLock) { if (!isRegistered()) { if (!mIsRegistered) { Log.w(TAG, "Attempting to unregister when already unregistered"); return; } Loading @@ -360,8 +367,8 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e); } } mEndpointManager.unregisterEndpoint(mEndpointInfo.getIdentifier().getEndpoint()); } releaseWakeLockOnExit(); } Loading @@ -376,7 +383,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub "openSessionRequestComplete for invalid session id=" + sessionId); } try { mHubInterface.endpointSessionOpenComplete(sessionId); getHubInterface().endpointSessionOpenComplete(sessionId); info.cancelSessionOpenTimeoutFuture(); info.setSessionState(Session.SessionState.ACTIVE); } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) { Loading Loading @@ -404,7 +411,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub Message halMessage = ContextHubServiceUtil.createHalMessage(message); if (callback == null) { try { mHubInterface.sendMessageToEndpoint(sessionId, halMessage); getHubInterface().sendMessageToEndpoint(sessionId, halMessage); } catch (RemoteException e) { Log.e( TAG, Loading Loading @@ -438,7 +445,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub }; ContextHubServiceTransaction transaction = mTransactionManager.createSessionMessageTransaction( mHubInterface, getHubInterface(), sessionId, halMessage, mPackageName, Loading Loading @@ -469,7 +476,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub status.messageSequenceNumber = messageSeqNumber; status.errorCode = errorCode; try { mHubInterface.sendMessageDeliveryStatusToEndpoint(sessionId, status); getHubInterface().sendMessageDeliveryStatusToEndpoint(sessionId, status); } catch (RemoteException e) { Log.w( TAG, Loading Loading @@ -553,14 +560,19 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub */ /* package */ void register() throws RemoteException { synchronized (mRegistrationLock) { if (isRegistered()) { registerLocked(); } } @GuardedBy("mRegistrationLock") private void registerLocked() throws RemoteException { if (mIsRegistered) { Log.w(TAG, "Attempting to register when already registered"); } else { mHubInterface.registerEndpoint(mHalEndpointInfo); mIsRegistered = true; } } } /* package */ void attachDeathRecipient() throws RemoteException { mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */); Loading Loading @@ -630,20 +642,28 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } /* package */ void onHalRestart() { /** * Handle the case where the underlying Context Hub HAL has restarted. * * @param hubInterface The new interface to the Context Hub HAL. */ /* package */ void onHalRestart(@NonNull IEndpointCommunication hubInterface) { synchronized (mOpenSessionLock) { for (int i = mSessionMap.size() - 1; i >= 0; i--) { int id = mSessionMap.keyAt(i); onCloseEndpointSession(id, Reason.HUB_RESET); } } synchronized (mRegistrationLock) { if (mIsRegistered) { mIsRegistered = false; mHubInterface = hubInterface; try { register(); registerLocked(); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL registerEndpoint", e); } } synchronized (mOpenSessionLock) { for (int i = mSessionMap.size() - 1; i >= 0; i--) { int id = mSessionMap.keyAt(i); onCloseEndpointSession(id, Reason.HUB_RESET); } } } Loading Loading @@ -901,4 +921,10 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub mEndpointManager.halCloseEndpointSessionNoThrow(sessionId, halReason); onCloseEndpointSession(sessionId, halReason); } private IEndpointCommunication getHubInterface() { synchronized (mRegistrationLock) { return mHubInterface; } } } services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +83 −48 Original line number Diff line number Diff line Loading @@ -85,8 +85,8 @@ import java.util.function.Consumer; private final Object mEndpointLock = new Object(); /** * The next available endpoint ID to register. Per EndpointId.aidl definition, dynamic * endpoint IDs must have the left-most bit as 1, and the values 0/-1 are invalid. * The next available endpoint ID to register. Per EndpointId.aidl definition, dynamic endpoint * IDs must have the left-most bit as 1, and the values 0/-1 are invalid. */ @GuardedBy("mEndpointLock") private long mNextEndpointId = -2; Loading @@ -100,6 +100,9 @@ import java.util.function.Consumer; /** Variables for managing session ID creation */ private final Object mSessionIdLock = new Object(); /** Variables for managing HAL restart */ private final Object mHalRestartLock = new Object(); /** A set of session IDs that have been reserved by an endpoint. */ @GuardedBy("mSessionIdLock") private final Set<Integer> mReservedSessionIds = Loading @@ -109,7 +112,7 @@ import java.util.function.Consumer; private int mNextSessionId = 0; /** Set true if init() succeeds */ private boolean mSessionIdsValid = false; private boolean mIsRegistered = false; /** The interface for endpoint communication (retrieved from HAL in init()) */ private IEndpointCommunication mHubInterface = null; Loading Loading @@ -189,14 +192,24 @@ import java.util.function.Consumer; /** * Initializes this class. * * This is separate from the constructor so that this may be passed into the callback registered * with the HAL. * <p>This is separate from the constructor so that this may be passed into the callback * registered with the HAL. * * @throws IllegalStateException if mHubInterface is null * @throws InstantiationException on unexpected failure * @throws UnsupportedOperationException if not supported by the HAL */ /* package */ void init() throws InstantiationException, UnsupportedOperationException { if (mSessionIdsValid) { /* package */ void init() throws IllegalStateException, InstantiationException, UnsupportedOperationException { synchronized (mHalRestartLock) { initLocked(); } } @GuardedBy("mHalRestartLock") private void initLocked() throws IllegalStateException, InstantiationException, UnsupportedOperationException { if (mIsRegistered) { throw new IllegalStateException("Already initialized"); } try { Loading @@ -209,9 +222,9 @@ import java.util.function.Consumer; contextHubInfo.toolchain = ""; contextHubInfo.supportedPermissions = new String[0]; info.hubDetails = HubInfo.HubDetails.contextHubInfo(contextHubInfo); mHubInterface = mContextHubProxy.registerEndpointHub( new ContextHubHalEndpointCallback(mHubInfoRegistry, this), info); mHubInterface = mContextHubProxy.registerEndpointHub( new ContextHubHalEndpointCallback(mHubInfoRegistry, this), info); if (mHubInterface == null) { throw new IllegalStateException("Received null IEndpointCommunication"); } Loading Loading @@ -250,7 +263,7 @@ import java.util.function.Consumer; synchronized (mSessionIdLock) { mNextSessionId = mMinSessionId; } mSessionIdsValid = true; mIsRegistered = true; } /** Loading @@ -268,7 +281,8 @@ import java.util.function.Consumer; String packageName, String attributionTag) throws RemoteException { if (!mSessionIdsValid) { synchronized (mHalRestartLock) { if (!mIsRegistered) { throw new IllegalStateException("ContextHubEndpointManager failed to initialize"); } ContextHubEndpointBroker broker; Loading Loading @@ -299,10 +313,12 @@ import java.util.function.Consumer; return null; } mRegistrationRecordDeque.add(new RegistrationRecord(broker.toString(), ACTION_REGISTERED)); mRegistrationRecordDeque.add( new RegistrationRecord(broker.toString(), ACTION_REGISTERED)); Log.d(TAG, "Registered endpoint with ID = " + endpointId); return IContextHubEndpoint.Stub.asInterface(broker); } } /** * Reserves an available session ID for an endpoint. Loading Loading @@ -351,6 +367,7 @@ import java.util.function.Consumer; * @param endpointId The ID of the endpoint to unregister. */ /* package */ void unregisterEndpoint(long endpointId) { Log.d(TAG, "Unregistering endpoint with ID = " + endpointId); ContextHubEndpointBroker broker = mEndpointMap.remove(endpointId); if (broker != null) { mRegistrationRecordDeque.add( Loading @@ -360,9 +377,25 @@ import java.util.function.Consumer; /** Invoked by the service when the Context Hub HAL restarts. */ /* package */ void onHalRestart() { synchronized (mHalRestartLock) { Log.d(TAG, "onHalRestart"); mIsRegistered = false; try { initLocked(); } catch (IllegalStateException | InstantiationException | UnsupportedOperationException e) { Log.e(TAG, "Failed to re-register ContextHubService:" + e.getMessage()); } for (ContextHubEndpointBroker broker : mEndpointMap.values()) { // The broker will close existing sessions and re-register itself broker.onHalRestart(); if (mIsRegistered) { // mHubInterface is guaranteed to be valid if mIsRegistered is true broker.onHalRestart(mHubInterface); } else { broker.unregister(); } } } } Loading Loading @@ -541,7 +574,9 @@ import java.util.function.Consumer; } } /** @return an available endpoint ID */ /** * @return an available endpoint ID */ private long getNewEndpointId() { synchronized (mEndpointLock) { if (mNextEndpointId >= 0) { Loading services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java +38 −3 Original line number Diff line number Diff line Loading @@ -105,6 +105,8 @@ public class ContextHubEndpointTest { @Mock private IContextHubEndpointCallback mMockCallback; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); private int mNumHalRestarts = 0; @Before public void setUp() throws RemoteException, InstantiationException { when(mMockContextHubWrapper.getHubs()).thenReturn(Collections.emptyList()); Loading Loading @@ -170,6 +172,13 @@ public class ContextHubEndpointTest { assertThat(statusCaptor.getValue().errorCode).isEqualTo(ErrorCode.DESTINATION_NOT_FOUND); } private void restartHalAndVerifyHubRegistration() throws RemoteException { mEndpointManager.onHalRestart(); mNumHalRestarts++; verify(mMockContextHubWrapper, times(mNumHalRestarts + 1)) .registerEndpointHub(any(), any()); } @Test public void testHalRestart() throws RemoteException { IContextHubEndpoint endpoint = registerExampleEndpoint(); Loading @@ -177,7 +186,7 @@ public class ContextHubEndpointTest { // Verify that the endpoint is still registered after a HAL restart HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); mEndpointManager.onHalRestart(); restartHalAndVerifyHubRegistration(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications, times(2)).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); Loading @@ -186,6 +195,33 @@ public class ContextHubEndpointTest { unregisterExampleEndpoint(endpoint); } @Test public void testHalRestartCanOpenSession() throws RemoteException { IContextHubEndpoint endpoint = registerExampleEndpoint(); // Verify that the endpoint is still registered after a HAL restart HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); restartHalAndVerifyHubRegistration(); 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 that the endpoint can open a session after a HAL restart 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); } @Test public void testHalRestartOnOpenSession() throws RemoteException { assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); Loading @@ -201,8 +237,7 @@ public class ContextHubEndpointTest { mEndpointManager.onEndpointSessionOpenComplete(sessionId); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE - 1); mEndpointManager.onHalRestart(); restartHalAndVerifyHubRegistration(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); Loading Loading
services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +51 −25 Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; /** Loading Loading @@ -92,7 +94,8 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub private final ScheduledExecutorService mSessionTimeoutExecutor; /** The proxy to talk to the Context Hub HAL for endpoint communication. */ private final IEndpointCommunication mHubInterface; @GuardedBy("mRegistrationLock") private IEndpointCommunication mHubInterface; /** The manager that registered this endpoint. */ private final ContextHubEndpointManager mEndpointManager; Loading Loading @@ -257,7 +260,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /* package */ ContextHubEndpointBroker( Context context, IEndpointCommunication hubInterface, @NonNull IEndpointCommunication hubInterface, ContextHubEndpointManager endpointManager, EndpointInfo halEndpointInfo, @NonNull IContextHubEndpointCallback callback, Loading Loading @@ -311,8 +314,12 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub synchronized (mOpenSessionLock) { try { mSessionMap.put(sessionId, new Session(destination, false)); mHubInterface.openEndpointSession( sessionId, halEndpointInfo.id, mHalEndpointInfo.id, serviceDescriptor); getHubInterface() .openEndpointSession( sessionId, halEndpointInfo.id, mHalEndpointInfo.id, serviceDescriptor); } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) { Log.e(TAG, "Exception while calling HAL openEndpointSession", e); cleanupSessionResources(sessionId); Loading Loading @@ -350,7 +357,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } synchronized (mRegistrationLock) { if (!isRegistered()) { if (!mIsRegistered) { Log.w(TAG, "Attempting to unregister when already unregistered"); return; } Loading @@ -360,8 +367,8 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e); } } mEndpointManager.unregisterEndpoint(mEndpointInfo.getIdentifier().getEndpoint()); } releaseWakeLockOnExit(); } Loading @@ -376,7 +383,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub "openSessionRequestComplete for invalid session id=" + sessionId); } try { mHubInterface.endpointSessionOpenComplete(sessionId); getHubInterface().endpointSessionOpenComplete(sessionId); info.cancelSessionOpenTimeoutFuture(); info.setSessionState(Session.SessionState.ACTIVE); } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) { Loading Loading @@ -404,7 +411,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub Message halMessage = ContextHubServiceUtil.createHalMessage(message); if (callback == null) { try { mHubInterface.sendMessageToEndpoint(sessionId, halMessage); getHubInterface().sendMessageToEndpoint(sessionId, halMessage); } catch (RemoteException e) { Log.e( TAG, Loading Loading @@ -438,7 +445,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub }; ContextHubServiceTransaction transaction = mTransactionManager.createSessionMessageTransaction( mHubInterface, getHubInterface(), sessionId, halMessage, mPackageName, Loading Loading @@ -469,7 +476,7 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub status.messageSequenceNumber = messageSeqNumber; status.errorCode = errorCode; try { mHubInterface.sendMessageDeliveryStatusToEndpoint(sessionId, status); getHubInterface().sendMessageDeliveryStatusToEndpoint(sessionId, status); } catch (RemoteException e) { Log.w( TAG, Loading Loading @@ -553,14 +560,19 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub */ /* package */ void register() throws RemoteException { synchronized (mRegistrationLock) { if (isRegistered()) { registerLocked(); } } @GuardedBy("mRegistrationLock") private void registerLocked() throws RemoteException { if (mIsRegistered) { Log.w(TAG, "Attempting to register when already registered"); } else { mHubInterface.registerEndpoint(mHalEndpointInfo); mIsRegistered = true; } } } /* package */ void attachDeathRecipient() throws RemoteException { mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */); Loading Loading @@ -630,20 +642,28 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } } /* package */ void onHalRestart() { /** * Handle the case where the underlying Context Hub HAL has restarted. * * @param hubInterface The new interface to the Context Hub HAL. */ /* package */ void onHalRestart(@NonNull IEndpointCommunication hubInterface) { synchronized (mOpenSessionLock) { for (int i = mSessionMap.size() - 1; i >= 0; i--) { int id = mSessionMap.keyAt(i); onCloseEndpointSession(id, Reason.HUB_RESET); } } synchronized (mRegistrationLock) { if (mIsRegistered) { mIsRegistered = false; mHubInterface = hubInterface; try { register(); registerLocked(); } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL registerEndpoint", e); } } synchronized (mOpenSessionLock) { for (int i = mSessionMap.size() - 1; i >= 0; i--) { int id = mSessionMap.keyAt(i); onCloseEndpointSession(id, Reason.HUB_RESET); } } } Loading Loading @@ -901,4 +921,10 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub mEndpointManager.halCloseEndpointSessionNoThrow(sessionId, halReason); onCloseEndpointSession(sessionId, halReason); } private IEndpointCommunication getHubInterface() { synchronized (mRegistrationLock) { return mHubInterface; } } }
services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +83 −48 Original line number Diff line number Diff line Loading @@ -85,8 +85,8 @@ import java.util.function.Consumer; private final Object mEndpointLock = new Object(); /** * The next available endpoint ID to register. Per EndpointId.aidl definition, dynamic * endpoint IDs must have the left-most bit as 1, and the values 0/-1 are invalid. * The next available endpoint ID to register. Per EndpointId.aidl definition, dynamic endpoint * IDs must have the left-most bit as 1, and the values 0/-1 are invalid. */ @GuardedBy("mEndpointLock") private long mNextEndpointId = -2; Loading @@ -100,6 +100,9 @@ import java.util.function.Consumer; /** Variables for managing session ID creation */ private final Object mSessionIdLock = new Object(); /** Variables for managing HAL restart */ private final Object mHalRestartLock = new Object(); /** A set of session IDs that have been reserved by an endpoint. */ @GuardedBy("mSessionIdLock") private final Set<Integer> mReservedSessionIds = Loading @@ -109,7 +112,7 @@ import java.util.function.Consumer; private int mNextSessionId = 0; /** Set true if init() succeeds */ private boolean mSessionIdsValid = false; private boolean mIsRegistered = false; /** The interface for endpoint communication (retrieved from HAL in init()) */ private IEndpointCommunication mHubInterface = null; Loading Loading @@ -189,14 +192,24 @@ import java.util.function.Consumer; /** * Initializes this class. * * This is separate from the constructor so that this may be passed into the callback registered * with the HAL. * <p>This is separate from the constructor so that this may be passed into the callback * registered with the HAL. * * @throws IllegalStateException if mHubInterface is null * @throws InstantiationException on unexpected failure * @throws UnsupportedOperationException if not supported by the HAL */ /* package */ void init() throws InstantiationException, UnsupportedOperationException { if (mSessionIdsValid) { /* package */ void init() throws IllegalStateException, InstantiationException, UnsupportedOperationException { synchronized (mHalRestartLock) { initLocked(); } } @GuardedBy("mHalRestartLock") private void initLocked() throws IllegalStateException, InstantiationException, UnsupportedOperationException { if (mIsRegistered) { throw new IllegalStateException("Already initialized"); } try { Loading @@ -209,9 +222,9 @@ import java.util.function.Consumer; contextHubInfo.toolchain = ""; contextHubInfo.supportedPermissions = new String[0]; info.hubDetails = HubInfo.HubDetails.contextHubInfo(contextHubInfo); mHubInterface = mContextHubProxy.registerEndpointHub( new ContextHubHalEndpointCallback(mHubInfoRegistry, this), info); mHubInterface = mContextHubProxy.registerEndpointHub( new ContextHubHalEndpointCallback(mHubInfoRegistry, this), info); if (mHubInterface == null) { throw new IllegalStateException("Received null IEndpointCommunication"); } Loading Loading @@ -250,7 +263,7 @@ import java.util.function.Consumer; synchronized (mSessionIdLock) { mNextSessionId = mMinSessionId; } mSessionIdsValid = true; mIsRegistered = true; } /** Loading @@ -268,7 +281,8 @@ import java.util.function.Consumer; String packageName, String attributionTag) throws RemoteException { if (!mSessionIdsValid) { synchronized (mHalRestartLock) { if (!mIsRegistered) { throw new IllegalStateException("ContextHubEndpointManager failed to initialize"); } ContextHubEndpointBroker broker; Loading Loading @@ -299,10 +313,12 @@ import java.util.function.Consumer; return null; } mRegistrationRecordDeque.add(new RegistrationRecord(broker.toString(), ACTION_REGISTERED)); mRegistrationRecordDeque.add( new RegistrationRecord(broker.toString(), ACTION_REGISTERED)); Log.d(TAG, "Registered endpoint with ID = " + endpointId); return IContextHubEndpoint.Stub.asInterface(broker); } } /** * Reserves an available session ID for an endpoint. Loading Loading @@ -351,6 +367,7 @@ import java.util.function.Consumer; * @param endpointId The ID of the endpoint to unregister. */ /* package */ void unregisterEndpoint(long endpointId) { Log.d(TAG, "Unregistering endpoint with ID = " + endpointId); ContextHubEndpointBroker broker = mEndpointMap.remove(endpointId); if (broker != null) { mRegistrationRecordDeque.add( Loading @@ -360,9 +377,25 @@ import java.util.function.Consumer; /** Invoked by the service when the Context Hub HAL restarts. */ /* package */ void onHalRestart() { synchronized (mHalRestartLock) { Log.d(TAG, "onHalRestart"); mIsRegistered = false; try { initLocked(); } catch (IllegalStateException | InstantiationException | UnsupportedOperationException e) { Log.e(TAG, "Failed to re-register ContextHubService:" + e.getMessage()); } for (ContextHubEndpointBroker broker : mEndpointMap.values()) { // The broker will close existing sessions and re-register itself broker.onHalRestart(); if (mIsRegistered) { // mHubInterface is guaranteed to be valid if mIsRegistered is true broker.onHalRestart(mHubInterface); } else { broker.unregister(); } } } } Loading Loading @@ -541,7 +574,9 @@ import java.util.function.Consumer; } } /** @return an available endpoint ID */ /** * @return an available endpoint ID */ private long getNewEndpointId() { synchronized (mEndpointLock) { if (mNextEndpointId >= 0) { Loading
services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java +38 −3 Original line number Diff line number Diff line Loading @@ -105,6 +105,8 @@ public class ContextHubEndpointTest { @Mock private IContextHubEndpointCallback mMockCallback; @Rule public final MockitoRule mockito = MockitoJUnit.rule(); private int mNumHalRestarts = 0; @Before public void setUp() throws RemoteException, InstantiationException { when(mMockContextHubWrapper.getHubs()).thenReturn(Collections.emptyList()); Loading Loading @@ -170,6 +172,13 @@ public class ContextHubEndpointTest { assertThat(statusCaptor.getValue().errorCode).isEqualTo(ErrorCode.DESTINATION_NOT_FOUND); } private void restartHalAndVerifyHubRegistration() throws RemoteException { mEndpointManager.onHalRestart(); mNumHalRestarts++; verify(mMockContextHubWrapper, times(mNumHalRestarts + 1)) .registerEndpointHub(any(), any()); } @Test public void testHalRestart() throws RemoteException { IContextHubEndpoint endpoint = registerExampleEndpoint(); Loading @@ -177,7 +186,7 @@ public class ContextHubEndpointTest { // Verify that the endpoint is still registered after a HAL restart HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); mEndpointManager.onHalRestart(); restartHalAndVerifyHubRegistration(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); verify(mMockEndpointCommunications, times(2)).registerEndpoint(statusCaptor.capture()); assertThat(statusCaptor.getValue().id.id).isEqualTo(assignedIdentifier.getEndpoint()); Loading @@ -186,6 +195,33 @@ public class ContextHubEndpointTest { unregisterExampleEndpoint(endpoint); } @Test public void testHalRestartCanOpenSession() throws RemoteException { IContextHubEndpoint endpoint = registerExampleEndpoint(); // Verify that the endpoint is still registered after a HAL restart HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); restartHalAndVerifyHubRegistration(); 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 that the endpoint can open a session after a HAL restart 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); } @Test public void testHalRestartOnOpenSession() throws RemoteException { assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE); Loading @@ -201,8 +237,7 @@ public class ContextHubEndpointTest { mEndpointManager.onEndpointSessionOpenComplete(sessionId); assertThat(mEndpointManager.getNumAvailableSessions()).isEqualTo(SESSION_ID_RANGE - 1); mEndpointManager.onHalRestart(); restartHalAndVerifyHubRegistration(); HubEndpointInfo assignedInfo = endpoint.getAssignedHubEndpointInfo(); HubEndpointIdentifier assignedIdentifier = assignedInfo.getIdentifier(); ArgumentCaptor<EndpointInfo> statusCaptor = ArgumentCaptor.forClass(EndpointInfo.class); Loading