Loading services/core/java/com/android/server/location/contexthub/ContextHubService.java +14 −4 Original line number Diff line number Diff line Loading @@ -798,7 +798,7 @@ public class ContextHubService extends IContextHubService.Stub { throws RemoteException { super.registerEndpoint_enforcePermission(); if (mEndpointManager == null) { Log.e(TAG, "ContextHubService.registerEndpoint: endpoint manager failed to initialize"); Log.e(TAG, "Endpoint manager failed to initialize"); throw new UnsupportedOperationException("Endpoint registration is not supported"); } return mEndpointManager.registerEndpoint(pendingHubEndpointInfo, callback); Loading @@ -809,7 +809,8 @@ public class ContextHubService extends IContextHubService.Stub { public void registerEndpointDiscoveryCallbackId( long endpointId, IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.registerEndpointDiscoveryCallbackId_enforcePermission(); // TODO(b/375487784): Implement this checkEndpointDiscoveryPreconditions(); mHubInfoRegistry.registerEndpointDiscoveryCallback(endpointId, callback); } @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) Loading @@ -818,7 +819,8 @@ public class ContextHubService extends IContextHubService.Stub { String serviceDescriptor, IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.registerEndpointDiscoveryCallbackDescriptor_enforcePermission(); // TODO(b/375487784): Implement this checkEndpointDiscoveryPreconditions(); mHubInfoRegistry.registerEndpointDiscoveryCallback(serviceDescriptor, callback); } @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) Loading @@ -826,7 +828,15 @@ public class ContextHubService extends IContextHubService.Stub { public void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.unregisterEndpointDiscoveryCallback_enforcePermission(); // TODO(b/375487784): Implement this checkEndpointDiscoveryPreconditions(); mHubInfoRegistry.unregisterEndpointDiscoveryCallback(callback); } private void checkEndpointDiscoveryPreconditions() { if (mHubInfoRegistry == null) { Log.e(TAG, "Hub endpoint registry failed to initialize"); throw new UnsupportedOperationException("Endpoint discovery is not supported"); } } /** Loading services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java +161 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ package com.android.server.location.contexthub; import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.HubServiceInfo; import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback; import android.hardware.location.HubInfo; import android.os.DeadObjectException; import android.os.RemoteException; import android.util.ArrayMap; import android.util.IndentingPrintWriter; Loading @@ -29,6 +31,9 @@ import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.BiConsumer; class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycleCallback { private static final String TAG = "HubInfoRegistry"; Loading @@ -43,6 +48,56 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl private final ArrayMap<HubEndpointInfo.HubEndpointIdentifier, HubEndpointInfo> mHubEndpointInfos = new ArrayMap<>(); /** * A wrapper class that is used to store arguments to * ContextHubManager.registerEndpointCallback. */ private static class DiscoveryCallback { private final IContextHubEndpointDiscoveryCallback mCallback; private final Optional<Long> mEndpointId; private final Optional<String> mServiceDescriptor; DiscoveryCallback(IContextHubEndpointDiscoveryCallback callback, long endpointId) { mCallback = callback; mEndpointId = Optional.of(endpointId); mServiceDescriptor = Optional.empty(); } DiscoveryCallback(IContextHubEndpointDiscoveryCallback callback, String serviceDescriptor) { mCallback = callback; mEndpointId = Optional.empty(); mServiceDescriptor = Optional.of(serviceDescriptor); } public IContextHubEndpointDiscoveryCallback getCallback() { return mCallback; } /** * @param info The hub endpoint info to check * @return true if info matches */ public boolean isMatch(HubEndpointInfo info) { if (mEndpointId.isPresent()) { return mEndpointId.get() == info.getIdentifier().getEndpoint(); } if (mServiceDescriptor.isPresent()) { for (HubServiceInfo serviceInfo : info.getServiceInfoCollection()) { if (mServiceDescriptor.get().equals(serviceInfo.getServiceDescriptor())) { return true; } } } return false; } } /* The list of discovery callbacks registered with the service */ @GuardedBy("mCallbackLock") private final List<DiscoveryCallback> mEndpointDiscoveryCallbacks = new ArrayList<>(); private final Object mCallbackLock = new Object(); HubInfoRegistry(IContextHubWrapper contextHubWrapper) { mContextHubWrapper = contextHubWrapper; refreshCachedHubs(); Loading Loading @@ -109,16 +164,50 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo); } } invokeForMatchingEndpoints( endpointInfos, (cb, infoList) -> { try { cb.onEndpointsStarted(infoList); } catch (RemoteException e) { if (e instanceof DeadObjectException) { Log.w(TAG, "onEndpointStarted: callback died, unregistering"); unregisterEndpointDiscoveryCallback(cb); } else { Log.e(TAG, "Exception while calling onEndpointsStarted", e); } } }); } @Override public void onEndpointStopped( HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason) { ArrayList<HubEndpointInfo> removedInfoList = new ArrayList<>(); synchronized (mLock) { for (HubEndpointInfo.HubEndpointIdentifier endpointId : endpointIds) { mHubEndpointInfos.remove(endpointId); HubEndpointInfo info = mHubEndpointInfos.remove(endpointId); if (info != null) { removedInfoList.add(info); } } } invokeForMatchingEndpoints( removedInfoList.toArray(new HubEndpointInfo[removedInfoList.size()]), (cb, infoList) -> { try { cb.onEndpointsStopped(infoList, reason); } catch (RemoteException e) { if (e instanceof DeadObjectException) { Log.w(TAG, "onEndpointStopped: callback died, unregistering"); unregisterEndpointDiscoveryCallback(cb); } else { Log.e(TAG, "Exception while calling onEndpointsStopped", e); } } }); } /** Return a list of {@link HubEndpointInfo} that represents endpoints with the matching id. */ Loading Loading @@ -151,6 +240,77 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl return searchResult; } /* package */ void registerEndpointDiscoveryCallback( long endpointId, IContextHubEndpointDiscoveryCallback callback) { Objects.requireNonNull(callback, "callback cannot be null"); synchronized (mCallbackLock) { checkCallbackAlreadyRegistered(callback); mEndpointDiscoveryCallbacks.add(new DiscoveryCallback(callback, endpointId)); } } /* package */ void registerEndpointDiscoveryCallback( String serviceDescriptor, IContextHubEndpointDiscoveryCallback callback) { Objects.requireNonNull(callback, "callback cannot be null"); synchronized (mCallbackLock) { checkCallbackAlreadyRegistered(callback); mEndpointDiscoveryCallbacks.add(new DiscoveryCallback(callback, serviceDescriptor)); } } /* package */ void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback) { Objects.requireNonNull(callback, "callback cannot be null"); synchronized (mCallbackLock) { for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { if (discoveryCallback.getCallback().asBinder() == callback.asBinder()) { mEndpointDiscoveryCallbacks.remove(discoveryCallback); break; } } } } private void checkCallbackAlreadyRegistered( IContextHubEndpointDiscoveryCallback callback) { synchronized (mCallbackLock) { for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { if (discoveryCallback.mCallback.asBinder() == callback.asBinder()) { throw new IllegalArgumentException("Callback is already registered"); } } } } /** * Iterates through all registered discovery callbacks and invokes a given callback for those * that match the endpoints the callback is targeted for. * * @param endpointInfos The list of endpoint infos to check for a match. * @param consumer The callback to invoke, which consumes the callback object and the list of * matched endpoint infos. */ private void invokeForMatchingEndpoints( HubEndpointInfo[] endpointInfos, BiConsumer<IContextHubEndpointDiscoveryCallback, HubEndpointInfo[]> consumer) { synchronized (mCallbackLock) { for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { ArrayList<HubEndpointInfo> infoList = new ArrayList<>(); for (HubEndpointInfo endpointInfo : endpointInfos) { if (discoveryCallback.isMatch(endpointInfo)) { infoList.add(endpointInfo); } } consumer.accept( discoveryCallback.getCallback(), infoList.toArray(new HubEndpointInfo[infoList.size()])); } } } void dump(IndentingPrintWriter ipw) { synchronized (mLock) { dumpLocked(ipw); Loading Loading
services/core/java/com/android/server/location/contexthub/ContextHubService.java +14 −4 Original line number Diff line number Diff line Loading @@ -798,7 +798,7 @@ public class ContextHubService extends IContextHubService.Stub { throws RemoteException { super.registerEndpoint_enforcePermission(); if (mEndpointManager == null) { Log.e(TAG, "ContextHubService.registerEndpoint: endpoint manager failed to initialize"); Log.e(TAG, "Endpoint manager failed to initialize"); throw new UnsupportedOperationException("Endpoint registration is not supported"); } return mEndpointManager.registerEndpoint(pendingHubEndpointInfo, callback); Loading @@ -809,7 +809,8 @@ public class ContextHubService extends IContextHubService.Stub { public void registerEndpointDiscoveryCallbackId( long endpointId, IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.registerEndpointDiscoveryCallbackId_enforcePermission(); // TODO(b/375487784): Implement this checkEndpointDiscoveryPreconditions(); mHubInfoRegistry.registerEndpointDiscoveryCallback(endpointId, callback); } @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) Loading @@ -818,7 +819,8 @@ public class ContextHubService extends IContextHubService.Stub { String serviceDescriptor, IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.registerEndpointDiscoveryCallbackDescriptor_enforcePermission(); // TODO(b/375487784): Implement this checkEndpointDiscoveryPreconditions(); mHubInfoRegistry.registerEndpointDiscoveryCallback(serviceDescriptor, callback); } @android.annotation.EnforcePermission(android.Manifest.permission.ACCESS_CONTEXT_HUB) Loading @@ -826,7 +828,15 @@ public class ContextHubService extends IContextHubService.Stub { public void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback) throws RemoteException { super.unregisterEndpointDiscoveryCallback_enforcePermission(); // TODO(b/375487784): Implement this checkEndpointDiscoveryPreconditions(); mHubInfoRegistry.unregisterEndpointDiscoveryCallback(callback); } private void checkEndpointDiscoveryPreconditions() { if (mHubInfoRegistry == null) { Log.e(TAG, "Hub endpoint registry failed to initialize"); throw new UnsupportedOperationException("Endpoint discovery is not supported"); } } /** Loading
services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java +161 −1 Original line number Diff line number Diff line Loading @@ -18,7 +18,9 @@ package com.android.server.location.contexthub; import android.hardware.contexthub.HubEndpointInfo; import android.hardware.contexthub.HubServiceInfo; import android.hardware.contexthub.IContextHubEndpointDiscoveryCallback; import android.hardware.location.HubInfo; import android.os.DeadObjectException; import android.os.RemoteException; import android.util.ArrayMap; import android.util.IndentingPrintWriter; Loading @@ -29,6 +31,9 @@ import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.function.BiConsumer; class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycleCallback { private static final String TAG = "HubInfoRegistry"; Loading @@ -43,6 +48,56 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl private final ArrayMap<HubEndpointInfo.HubEndpointIdentifier, HubEndpointInfo> mHubEndpointInfos = new ArrayMap<>(); /** * A wrapper class that is used to store arguments to * ContextHubManager.registerEndpointCallback. */ private static class DiscoveryCallback { private final IContextHubEndpointDiscoveryCallback mCallback; private final Optional<Long> mEndpointId; private final Optional<String> mServiceDescriptor; DiscoveryCallback(IContextHubEndpointDiscoveryCallback callback, long endpointId) { mCallback = callback; mEndpointId = Optional.of(endpointId); mServiceDescriptor = Optional.empty(); } DiscoveryCallback(IContextHubEndpointDiscoveryCallback callback, String serviceDescriptor) { mCallback = callback; mEndpointId = Optional.empty(); mServiceDescriptor = Optional.of(serviceDescriptor); } public IContextHubEndpointDiscoveryCallback getCallback() { return mCallback; } /** * @param info The hub endpoint info to check * @return true if info matches */ public boolean isMatch(HubEndpointInfo info) { if (mEndpointId.isPresent()) { return mEndpointId.get() == info.getIdentifier().getEndpoint(); } if (mServiceDescriptor.isPresent()) { for (HubServiceInfo serviceInfo : info.getServiceInfoCollection()) { if (mServiceDescriptor.get().equals(serviceInfo.getServiceDescriptor())) { return true; } } } return false; } } /* The list of discovery callbacks registered with the service */ @GuardedBy("mCallbackLock") private final List<DiscoveryCallback> mEndpointDiscoveryCallbacks = new ArrayList<>(); private final Object mCallbackLock = new Object(); HubInfoRegistry(IContextHubWrapper contextHubWrapper) { mContextHubWrapper = contextHubWrapper; refreshCachedHubs(); Loading Loading @@ -109,16 +164,50 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl mHubEndpointInfos.put(endpointInfo.getIdentifier(), endpointInfo); } } invokeForMatchingEndpoints( endpointInfos, (cb, infoList) -> { try { cb.onEndpointsStarted(infoList); } catch (RemoteException e) { if (e instanceof DeadObjectException) { Log.w(TAG, "onEndpointStarted: callback died, unregistering"); unregisterEndpointDiscoveryCallback(cb); } else { Log.e(TAG, "Exception while calling onEndpointsStarted", e); } } }); } @Override public void onEndpointStopped( HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason) { ArrayList<HubEndpointInfo> removedInfoList = new ArrayList<>(); synchronized (mLock) { for (HubEndpointInfo.HubEndpointIdentifier endpointId : endpointIds) { mHubEndpointInfos.remove(endpointId); HubEndpointInfo info = mHubEndpointInfos.remove(endpointId); if (info != null) { removedInfoList.add(info); } } } invokeForMatchingEndpoints( removedInfoList.toArray(new HubEndpointInfo[removedInfoList.size()]), (cb, infoList) -> { try { cb.onEndpointsStopped(infoList, reason); } catch (RemoteException e) { if (e instanceof DeadObjectException) { Log.w(TAG, "onEndpointStopped: callback died, unregistering"); unregisterEndpointDiscoveryCallback(cb); } else { Log.e(TAG, "Exception while calling onEndpointsStopped", e); } } }); } /** Return a list of {@link HubEndpointInfo} that represents endpoints with the matching id. */ Loading Loading @@ -151,6 +240,77 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl return searchResult; } /* package */ void registerEndpointDiscoveryCallback( long endpointId, IContextHubEndpointDiscoveryCallback callback) { Objects.requireNonNull(callback, "callback cannot be null"); synchronized (mCallbackLock) { checkCallbackAlreadyRegistered(callback); mEndpointDiscoveryCallbacks.add(new DiscoveryCallback(callback, endpointId)); } } /* package */ void registerEndpointDiscoveryCallback( String serviceDescriptor, IContextHubEndpointDiscoveryCallback callback) { Objects.requireNonNull(callback, "callback cannot be null"); synchronized (mCallbackLock) { checkCallbackAlreadyRegistered(callback); mEndpointDiscoveryCallbacks.add(new DiscoveryCallback(callback, serviceDescriptor)); } } /* package */ void unregisterEndpointDiscoveryCallback(IContextHubEndpointDiscoveryCallback callback) { Objects.requireNonNull(callback, "callback cannot be null"); synchronized (mCallbackLock) { for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { if (discoveryCallback.getCallback().asBinder() == callback.asBinder()) { mEndpointDiscoveryCallbacks.remove(discoveryCallback); break; } } } } private void checkCallbackAlreadyRegistered( IContextHubEndpointDiscoveryCallback callback) { synchronized (mCallbackLock) { for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { if (discoveryCallback.mCallback.asBinder() == callback.asBinder()) { throw new IllegalArgumentException("Callback is already registered"); } } } } /** * Iterates through all registered discovery callbacks and invokes a given callback for those * that match the endpoints the callback is targeted for. * * @param endpointInfos The list of endpoint infos to check for a match. * @param consumer The callback to invoke, which consumes the callback object and the list of * matched endpoint infos. */ private void invokeForMatchingEndpoints( HubEndpointInfo[] endpointInfos, BiConsumer<IContextHubEndpointDiscoveryCallback, HubEndpointInfo[]> consumer) { synchronized (mCallbackLock) { for (DiscoveryCallback discoveryCallback : mEndpointDiscoveryCallbacks) { ArrayList<HubEndpointInfo> infoList = new ArrayList<>(); for (HubEndpointInfo endpointInfo : endpointInfos) { if (discoveryCallback.isMatch(endpointInfo)) { infoList.add(endpointInfo); } } consumer.accept( discoveryCallback.getCallback(), infoList.toArray(new HubEndpointInfo[infoList.size()])); } } } void dump(IndentingPrintWriter ipw) { synchronized (mLock) { dumpLocked(ipw); Loading