diff options
6 files changed, 237 insertions, 24 deletions
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java index 7155cd0fc719..4a533f42ffea 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java @@ -27,6 +27,10 @@ import android.os.IBinder; import android.os.RemoteException; import android.util.Log; +import com.android.internal.annotations.GuardedBy; + +import java.util.HashSet; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -60,6 +64,20 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub /** True if this endpoint is registered with the service. */ private AtomicBoolean mIsRegistered = new AtomicBoolean(true); + private final Object mOpenSessionLock = new Object(); + + /** The set of session IDs that are pending remote acceptance */ + @GuardedBy("mOpenSessionLock") + private final Set<Integer> mPendingSessionIds = new HashSet<>(); + + /** The set of session IDs that are actively enabled by this endpoint */ + @GuardedBy("mOpenSessionLock") + private final Set<Integer> mActiveSessionIds = new HashSet<>(); + + /** The set of session IDs that are actively enabled by the remote endpoint */ + @GuardedBy("mOpenSessionLock") + private final Set<Integer> mActiveRemoteSessionIds = new HashSet<>(); + /* package */ ContextHubEndpointBroker( Context context, IContextHubWrapper contextHubProxy, @@ -86,16 +104,24 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered"); int sessionId = mEndpointManager.reserveSessionId(); EndpointInfo halEndpointInfo = ContextHubServiceUtil.convertHalEndpointInfo(destination); - try { - mContextHubProxy.openEndpointSession( - sessionId, halEndpointInfo.id, mHalEndpointInfo.id, serviceDescriptor); - } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) { - Log.e(TAG, "Exception while calling HAL openEndpointSession", e); - mEndpointManager.returnSessionId(sessionId); - throw e; - } - return sessionId; + synchronized (mOpenSessionLock) { + try { + mPendingSessionIds.add(sessionId); + mContextHubProxy.openEndpointSession( + sessionId, + halEndpointInfo.id, + mHalEndpointInfo.id, + serviceDescriptor); + } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) { + Log.e(TAG, "Exception while calling HAL openEndpointSession", e); + mPendingSessionIds.remove(sessionId); + mEndpointManager.returnSessionId(sessionId); + throw e; + } + + return sessionId; + } } @Override @@ -111,11 +137,6 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } @Override - public void openSessionRequestComplete(int sessionId) { - // TODO(b/378487799): Implement this - } - - @Override public void unregister() { ContextHubServiceUtil.checkPermissions(mContext); mIsRegistered.set(false); @@ -124,11 +145,34 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub } catch (RemoteException e) { Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e); } - // TODO(b/378487799): Release reserved session IDs + synchronized (mOpenSessionLock) { + for (int id : mPendingSessionIds) { + mEndpointManager.returnSessionId(id); + } + for (int id : mActiveSessionIds) { + mEndpointManager.returnSessionId(id); + } + mPendingSessionIds.clear(); + mActiveSessionIds.clear(); + mActiveRemoteSessionIds.clear(); + } mEndpointManager.unregisterEndpoint(mEndpointInfo.getIdentifier().getEndpoint()); } @Override + public void openSessionRequestComplete(int sessionId) { + ContextHubServiceUtil.checkPermissions(mContext); + synchronized (mOpenSessionLock) { + try { + mContextHubProxy.endpointSessionOpenComplete(sessionId); + mActiveRemoteSessionIds.add(sessionId); + } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) { + Log.e(TAG, "Exception while calling endpointSessionOpenComplete", e); + } + } + } + + @Override public void sendMessage( int sessionId, HubMessage message, IContextHubTransactionCallback callback) { // TODO(b/381102453): Implement this @@ -150,4 +194,53 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */); } } + + /* package */ void onEndpointSessionOpenRequest( + int sessionId, HubEndpointInfo initiator, String serviceDescriptor) { + if (mContextHubEndpointCallback != null) { + try { + mContextHubEndpointCallback.onSessionOpenRequest( + sessionId, initiator, serviceDescriptor); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while calling onSessionOpenRequest", e); + } + } + } + + /* package */ void onCloseEndpointSession(int sessionId, byte reason) { + synchronized (mOpenSessionLock) { + mPendingSessionIds.remove(sessionId); + mActiveSessionIds.remove(sessionId); + mActiveRemoteSessionIds.remove(sessionId); + } + if (mContextHubEndpointCallback != null) { + try { + mContextHubEndpointCallback.onSessionClosed(sessionId, reason); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while calling onSessionClosed", e); + } + } + } + + /* package */ void onEndpointSessionOpenComplete(int sessionId) { + synchronized (mOpenSessionLock) { + mPendingSessionIds.remove(sessionId); + mActiveSessionIds.add(sessionId); + } + if (mContextHubEndpointCallback != null) { + try { + mContextHubEndpointCallback.onSessionOpenComplete(sessionId); + } catch (RemoteException e) { + Log.e(TAG, "RemoteException while calling onSessionClosed", e); + } + } + } + + /* package */ boolean hasSessionId(int sessionId) { + synchronized (mOpenSessionLock) { + return mPendingSessionIds.contains(sessionId) + || mActiveSessionIds.contains(sessionId) + || mActiveRemoteSessionIds.contains(sessionId); + } + } } diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java index fb64f99e5904..8c5095f35f0d 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointManager.java @@ -38,7 +38,8 @@ import java.util.concurrent.ConcurrentHashMap; * * @hide */ -/* package */ class ContextHubEndpointManager { +/* package */ class ContextHubEndpointManager + implements ContextHubHalEndpointCallback.IEndpointSessionCallback { private static final String TAG = "ContextHubEndpointManager"; /** The hub ID of the Context Hub Service. */ @@ -56,6 +57,8 @@ import java.util.concurrent.ConcurrentHashMap; /** The proxy to talk to the Context Hub. */ private final IContextHubWrapper mContextHubProxy; + private final HubInfoRegistry mHubInfoRegistry; + /** A map of endpoint IDs to brokers currently registered. */ private final Map<Long, ContextHubEndpointBroker> mEndpointMap = new ConcurrentHashMap<>(); @@ -85,9 +88,11 @@ import java.util.concurrent.ConcurrentHashMap; /** Initialized to true if all initialization in the constructor succeeds. */ private final boolean mSessionIdsValid; - /* package */ ContextHubEndpointManager(Context context, IContextHubWrapper contextHubProxy) { + /* package */ ContextHubEndpointManager( + Context context, IContextHubWrapper contextHubProxy, HubInfoRegistry hubInfoRegistry) { mContext = context; mContextHubProxy = contextHubProxy; + mHubInfoRegistry = hubInfoRegistry; int[] range = null; try { range = mContextHubProxy.requestSessionIdRange(SERVICE_SESSION_RANGE); @@ -210,6 +215,70 @@ import java.util.concurrent.ConcurrentHashMap; mEndpointMap.remove(endpointId); } + @Override + public void onEndpointSessionOpenRequest( + int sessionId, + HubEndpointInfo.HubEndpointIdentifier destination, + HubEndpointInfo.HubEndpointIdentifier initiator, + String serviceDescriptor) { + if (destination.getHub() != SERVICE_HUB_ID) { + Log.e( + TAG, + "onEndpointSessionOpenRequest: invalid destination hub ID: " + + destination.getHub()); + return; + } + ContextHubEndpointBroker broker = mEndpointMap.get(destination.getEndpoint()); + if (broker == null) { + Log.e( + TAG, + "onEndpointSessionOpenRequest: unknown destination endpoint ID: " + + destination.getEndpoint()); + return; + } + HubEndpointInfo initiatorInfo = mHubInfoRegistry.getEndpointInfo(initiator); + if (initiatorInfo == null) { + Log.e( + TAG, + "onEndpointSessionOpenRequest: unknown initiator endpoint ID: " + + initiator.getEndpoint()); + return; + } + broker.onEndpointSessionOpenRequest(sessionId, initiatorInfo, serviceDescriptor); + } + + @Override + public void onCloseEndpointSession(int sessionId, byte reason) { + boolean callbackInvoked = false; + for (ContextHubEndpointBroker broker : mEndpointMap.values()) { + if (broker.hasSessionId(sessionId)) { + broker.onCloseEndpointSession(sessionId, reason); + callbackInvoked = true; + break; + } + } + + if (!callbackInvoked) { + Log.w(TAG, "onCloseEndpointSession: unknown session ID " + sessionId); + } + } + + @Override + public void onEndpointSessionOpenComplete(int sessionId) { + boolean callbackInvoked = false; + for (ContextHubEndpointBroker broker : mEndpointMap.values()) { + if (broker.hasSessionId(sessionId)) { + broker.onEndpointSessionOpenComplete(sessionId); + callbackInvoked = true; + break; + } + } + + if (!callbackInvoked) { + Log.w(TAG, "onEndpointSessionOpenComplete: unknown session ID " + sessionId); + } + } + /** @return an available endpoint ID */ private long getNewEndpointId() { synchronized (mEndpointLock) { @@ -220,6 +289,9 @@ import java.util.concurrent.ConcurrentHashMap; } } + /** + * @return true if the provided session ID range is valid + */ private boolean isSessionIdRangeValid(int minId, int maxId) { return (minId <= maxId) && (minId >= 0) && (maxId >= 0); } diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java index c05f7a0c0e00..8e72553a9c52 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubHalEndpointCallback.java @@ -26,6 +26,7 @@ import android.os.RemoteException; public class ContextHubHalEndpointCallback extends android.hardware.contexthub.IEndpointCallback.Stub { private final IEndpointLifecycleCallback mEndpointLifecycleCallback; + private final IEndpointSessionCallback mEndpointSessionCallback; /** Interface for listening for endpoint start and stop events. */ public interface IEndpointLifecycleCallback { @@ -36,8 +37,27 @@ public class ContextHubHalEndpointCallback void onEndpointStopped(HubEndpointInfo.HubEndpointIdentifier[] endpointIds, byte reason); } - ContextHubHalEndpointCallback(IEndpointLifecycleCallback endpointLifecycleCallback) { + /** Interface for listening for endpoint session events. */ + public interface IEndpointSessionCallback { + /** Called when an endpoint session open is requested by the HAL. */ + void onEndpointSessionOpenRequest( + int sessionId, + HubEndpointInfo.HubEndpointIdentifier destinationId, + HubEndpointInfo.HubEndpointIdentifier initiatorId, + String serviceDescriptor); + + /** Called when a endpoint close session is completed. */ + void onCloseEndpointSession(int sessionId, byte reason); + + /** Called when a requested endpoint open session is completed */ + void onEndpointSessionOpenComplete(int sessionId); + } + + ContextHubHalEndpointCallback( + IEndpointLifecycleCallback endpointLifecycleCallback, + IEndpointSessionCallback endpointSessionCallback) { mEndpointLifecycleCallback = endpointLifecycleCallback; + mEndpointSessionCallback = endpointSessionCallback; } @Override @@ -72,14 +92,23 @@ public class ContextHubHalEndpointCallback @Override public void onEndpointSessionOpenRequest( - int i, EndpointId endpointId, EndpointId endpointId1, String s) - throws RemoteException {} + int i, EndpointId destination, EndpointId initiator, String s) throws RemoteException { + HubEndpointInfo.HubEndpointIdentifier destinationId = + new HubEndpointInfo.HubEndpointIdentifier(destination.hubId, destination.id); + HubEndpointInfo.HubEndpointIdentifier initiatorId = + new HubEndpointInfo.HubEndpointIdentifier(initiator.hubId, initiator.id); + mEndpointSessionCallback.onEndpointSessionOpenRequest(i, destinationId, initiatorId, s); + } @Override - public void onCloseEndpointSession(int i, byte b) throws RemoteException {} + public void onCloseEndpointSession(int i, byte b) throws RemoteException { + mEndpointSessionCallback.onCloseEndpointSession(i, b); + } @Override - public void onEndpointSessionOpenComplete(int i) throws RemoteException {} + public void onEndpointSessionOpenComplete(int i) throws RemoteException { + mEndpointSessionCallback.onEndpointSessionOpenComplete(i); + } @Override public int getInterfaceVersion() throws RemoteException { diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index 0d926b99217d..0b47a61341f7 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -333,7 +333,8 @@ public class ContextHubService extends IContextHubService.Stub { HubInfoRegistry registry; try { registry = new HubInfoRegistry(mContextHubWrapper); - mEndpointManager = new ContextHubEndpointManager(mContext, mContextHubWrapper); + mEndpointManager = + new ContextHubEndpointManager(mContext, mContextHubWrapper, registry); Log.i(TAG, "Enabling generic offload API"); } catch (UnsupportedOperationException e) { mEndpointManager = null; @@ -533,7 +534,7 @@ public class ContextHubService extends IContextHubService.Stub { } try { mContextHubWrapper.registerEndpointCallback( - new ContextHubHalEndpointCallback(mHubInfoRegistry)); + new ContextHubHalEndpointCallback(mHubInfoRegistry, mEndpointManager)); } catch (RemoteException | UnsupportedOperationException e) { Log.e(TAG, "Exception while registering IEndpointCallback", e); } diff --git a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java index d2b2331d54f3..b91249204199 100644 --- a/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java +++ b/services/core/java/com/android/server/location/contexthub/HubInfoRegistry.java @@ -87,6 +87,12 @@ class HubInfoRegistry implements ContextHubHalEndpointCallback.IEndpointLifecycl } } + public HubEndpointInfo getEndpointInfo(HubEndpointInfo.HubEndpointIdentifier id) { + synchronized (mLock) { + return mHubEndpointInfos.get(id); + } + } + /** Invoked when HAL restarts */ public void onHalRestart() { synchronized (mLock) { diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java index c79dc84ec2af..6cb942980403 100644 --- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java +++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java @@ -261,6 +261,9 @@ public abstract class IContextHubWrapper { public void unregisterEndpoint(android.hardware.contexthub.EndpointInfo info) throws RemoteException {} + /** Notifies the completion of a session opened by the HAL */ + public void endpointSessionOpenComplete(int sessionId) throws RemoteException {} + /** * @return True if this version of the Contexthub HAL supports Location setting notifications. */ @@ -745,6 +748,15 @@ public abstract class IContextHubWrapper { hub.unregisterEndpoint(info); } + @Override + public void endpointSessionOpenComplete(int sessionId) throws RemoteException { + android.hardware.contexthub.IContextHub hub = getHub(); + if (hub == null) { + return; + } + hub.endpointSessionOpenComplete(sessionId); + } + public boolean supportsLocationSettingNotifications() { return true; } |