Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4be8545d authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I1a50d511,I200c64e2,I5d5fc99b into main

* changes:
  Implements death recipient handler at ContextHubEndpointBroker
  Implements ContextHubEndpointBroker unregisterEndpoint
  Implements ContextHubEndpointBroker open/closeEndpointSession
parents fb3baa77 2e7c7652
Loading
Loading
Loading
Loading
+59 −10
Original line number Diff line number Diff line
@@ -24,6 +24,11 @@ import android.hardware.contexthub.HubServiceInfo;
import android.hardware.contexthub.IContextHubEndpoint;
import android.hardware.contexthub.IContextHubEndpointCallback;
import android.hardware.location.IContextHubTransactionCallback;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A class that represents a broker for the endpoint registered by the client app. This class
@@ -31,7 +36,8 @@ import android.hardware.location.IContextHubTransactionCallback;
 *
 * @hide
 */
public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub
        implements IBinder.DeathRecipient {
    private static final String TAG = "ContextHubEndpointBroker";

    /** The context of the service. */
@@ -52,6 +58,9 @@ 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);

    /* package */ ContextHubEndpointBroker(
            Context context,
            IContextHubWrapper contextHubProxy,
@@ -72,27 +81,55 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
    }

    @Override
    public int openSession(HubEndpointInfo destination, HubServiceInfo serviceInfo) {
        // TODO(b/378487799): Implement this
        return 0;
    public int openSession(HubEndpointInfo destination, HubServiceInfo serviceInfo)
            throws RemoteException {
        ContextHubServiceUtil.checkPermissions(mContext);
        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,
                    serviceInfo == null ? null : serviceInfo.getServiceDescriptor());
        } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
            Log.e(TAG, "Exception while calling HAL openEndpointSession", e);
            mEndpointManager.returnSessionId(sessionId);
            throw e;
        }

    @Override
    public void closeSession(int sessionId, int reason) {
        // TODO(b/378487799): Implement this
        return sessionId;
    }

    @Override
    public void closeSession(int sessionId, int reason) throws RemoteException {
        ContextHubServiceUtil.checkPermissions(mContext);
        if (!mIsRegistered.get()) throw new IllegalStateException("Endpoint is not registered");
        try {
            mContextHubProxy.closeEndpointSession(sessionId, (byte) reason);
        } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
            Log.e(TAG, "Exception while calling HAL closeEndpointSession", e);
            throw e;
        }
    }

    @Override
    public void openSessionRequestComplete(int sessionId) {
        // TODO(b/378487799): Implement this

    }

    @Override
    public void unregister() {
        // TODO(b/378487799): Implement this

        ContextHubServiceUtil.checkPermissions(mContext);
        mIsRegistered.set(false);
        try {
            mContextHubProxy.unregisterEndpoint(mHalEndpointInfo);
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException while calling HAL unregisterEndpoint", e);
        }
        // TODO(b/378487799): Release reserved session IDs
        mEndpointManager.unregisterEndpoint(mEndpointInfo.getIdentifier().getEndpoint());
    }

    @Override
@@ -105,4 +142,16 @@ public class ContextHubEndpointBroker extends IContextHubEndpoint.Stub {
    public void sendMessageDeliveryStatus(int sessionId, int messageSeqNumber, byte errorCode) {
        // TODO(b/381102453): Implement this
    }

    /** Invoked when the underlying binder of this broker has died at the client process. */
    @Override
    public void binderDied() {
        unregister();
    }

    /* package */ void attachDeathRecipient() throws RemoteException {
        if (mContextHubEndpointCallback != null) {
            mContextHubEndpointCallback.asBinder().linkToDeath(this, 0 /* flags */);
        }
    }
}
+117 −2
Original line number Diff line number Diff line
@@ -22,11 +22,15 @@ import android.hardware.contexthub.HubEndpointInfo;
import android.hardware.contexthub.IContextHubEndpoint;
import android.hardware.contexthub.IContextHubEndpointCallback;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.util.Log;

import com.android.internal.annotations.GuardedBy;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
@@ -40,6 +44,12 @@ import java.util.concurrent.ConcurrentHashMap;
    /** The hub ID of the Context Hub Service. */
    private static final long SERVICE_HUB_ID = 0x416e64726f696400L;

    /** The range of session IDs to use for endpoints */
    private static final int SERVICE_SESSION_RANGE = 1024;

    /** The length of the array that should be returned by HAL requestSessionIdRange */
    private static final int SERVICE_SESSION_RANGE_LENGTH = 2;

    /** The context of the service. */
    private final Context mContext;

@@ -55,9 +65,57 @@ import java.util.concurrent.ConcurrentHashMap;
    @GuardedBy("mEndpointLock")
    private long mNextEndpointId = 0;

    /** The minimum session ID reservable by endpoints (retrieved from HAL) */
    private final int mMinSessionId;

    /** The minimum session ID reservable by endpoints (retrieved from HAL) */
    private final int mMaxSessionId;

    /** Variables for managing session ID creation */
    private final Object mSessionIdLock = new Object();

    /** A set of session IDs that have been reserved by an endpoint. */
    @GuardedBy("mSessionIdLock")
    private final Set<Integer> mReservedSessionIds =
            Collections.newSetFromMap(new HashMap<Integer, Boolean>());

    @GuardedBy("mSessionIdLock")
    private int mNextSessionId = 0;

    /** Initialized to true if all initialization in the constructor succeeds. */
    private final boolean mSessionIdsValid;

    /* package */ ContextHubEndpointManager(Context context, IContextHubWrapper contextHubProxy) {
        mContext = context;
        mContextHubProxy = contextHubProxy;
        int[] range = null;
        try {
            range = mContextHubProxy.requestSessionIdRange(SERVICE_SESSION_RANGE);
            if (range != null && range.length < SERVICE_SESSION_RANGE_LENGTH) {
                Log.e(TAG, "Invalid session ID range: range array size = " + range.length);
                range = null;
            }
        } catch (RemoteException | IllegalArgumentException | ServiceSpecificException e) {
            Log.e(TAG, "Exception while calling HAL requestSessionIdRange", e);
        }

        if (range == null) {
            mMinSessionId = -1;
            mMaxSessionId = -1;
            mSessionIdsValid = false;
        } else {
            mMinSessionId = range[0];
            mMaxSessionId = range[1];
            if (!isSessionIdRangeValid(mMinSessionId, mMaxSessionId)) {
                Log.e(
                        TAG,
                        "Invalid session ID range: max=" + mMaxSessionId + " min=" + mMinSessionId);
                mSessionIdsValid = false;
            } else {
                mNextSessionId = mMinSessionId;
                mSessionIdsValid = true;
            }
        }
    }

    /**
@@ -71,6 +129,9 @@ import java.util.concurrent.ConcurrentHashMap;
    /* package */ IContextHubEndpoint registerEndpoint(
            HubEndpointInfo pendingEndpointInfo, IContextHubEndpointCallback callback)
            throws RemoteException {
        if (!mSessionIdsValid) {
            throw new IllegalStateException("ContextHubEndpointManager failed to initialize");
        }
        ContextHubEndpointBroker broker;
        long endpointId = getNewEndpointId();
        EndpointInfo halEndpointInfo =
@@ -91,15 +152,65 @@ import java.util.concurrent.ConcurrentHashMap;
                        callback);
        mEndpointMap.put(endpointId, broker);

        // TODO(b/378487799): Add death recipient
        try {
            broker.attachDeathRecipient();
        } catch (RemoteException e) {
            // The client process has died, so we close the connection and return null
            Log.e(TAG, "Failed to attach death recipient to client", e);
            broker.unregister();
            return null;
        }

        Log.d(TAG, "Registered endpoint with ID = " + endpointId);
        return IContextHubEndpoint.Stub.asInterface(broker);
    }

    /**
     * @return an available endpoint ID
     * Reserves an available session ID for an endpoint.
     *
     * @throws IllegalStateException if no session ID was available.
     * @return The reserved session ID.
     */
    /* package */ int reserveSessionId() {
        int id = -1;
        synchronized (mSessionIdLock) {
            final int maxCapacity = mMaxSessionId - mMinSessionId + 1;
            if (mReservedSessionIds.size() >= maxCapacity) {
                throw new IllegalStateException("Too many sessions reserved");
            }

            id = mNextSessionId;
            for (int i = mMinSessionId; i <= mMaxSessionId; i++) {
                if (!mReservedSessionIds.contains(id)) {
                    mNextSessionId = (id == mMaxSessionId) ? mMinSessionId : id + 1;
                    break;
                }

                id = (id == mMaxSessionId) ? mMinSessionId : id + 1;
            }

            mReservedSessionIds.add(id);
        }
        return id;
    }

    /** Returns a previously reserved session ID through {@link #reserveSessionId()}. */
    /* package */ void returnSessionId(int sessionId) {
        synchronized (mSessionIdLock) {
            mReservedSessionIds.remove(sessionId);
        }
    }

    /**
     * Unregisters an endpoint given its ID.
     *
     * @param endpointId The ID of the endpoint to unregister.
     */
    /* package */ void unregisterEndpoint(long endpointId) {
        mEndpointMap.remove(endpointId);
    }

    /** @return an available endpoint ID */
    private long getNewEndpointId() {
        synchronized (mEndpointLock) {
            if (mNextEndpointId == Long.MAX_VALUE) {
@@ -108,4 +219,8 @@ import java.util.concurrent.ConcurrentHashMap;
            return mNextEndpointId++;
        }
    }

    private boolean isSessionIdRangeValid(int minId, int maxId) {
        return (minId <= maxId) && (minId >= 0) && (maxId >= 0);
    }
}
+60 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.server.location.contexthub;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.chre.flags.Flags;
import android.hardware.contexthub.EndpointId;
import android.hardware.contexthub.HostEndpointInfo;
import android.hardware.contexthub.HubEndpointInfo;
import android.hardware.contexthub.MessageDeliveryStatus;
@@ -243,6 +244,23 @@ public abstract class IContextHubWrapper {
    public void registerEndpoint(android.hardware.contexthub.EndpointInfo info)
            throws RemoteException {}

    /** Unregisters a previously registered endpoint */
    public int[] requestSessionIdRange(int size) throws RemoteException {
        return null;
    }

    /** Opens an endpoint session between two endpoints */
    public void openEndpointSession(
            int sessionId, EndpointId destination, EndpointId initiator, String serviceDescriptor)
            throws RemoteException {}

    /** Closes a previously opened endpoint */
    public void closeEndpointSession(int sessionId, byte reason) throws RemoteException {}

    /** Unregisters a previously registered endpoint */
    public void unregisterEndpoint(android.hardware.contexthub.EndpointInfo info)
            throws RemoteException {}

    /**
     * @return True if this version of the Contexthub HAL supports Location setting notifications.
     */
@@ -685,6 +703,48 @@ public abstract class IContextHubWrapper {
            hub.registerEndpoint(info);
        }

        @Override
        public int[] requestSessionIdRange(int size) throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return null;
            }
            return hub.requestSessionIdRange(size);
        }

        @Override
        public void openEndpointSession(
                int sessionId,
                EndpointId destination,
                EndpointId initiator,
                String serviceDescriptor)
                throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }
            hub.openEndpointSession(sessionId, destination, initiator, serviceDescriptor);
        }

        @Override
        public void closeEndpointSession(int sessionId, byte reason) throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }
            hub.closeEndpointSession(sessionId, reason);
        }

        @Override
        public void unregisterEndpoint(android.hardware.contexthub.EndpointInfo info)
                throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }
            hub.unregisterEndpoint(info);
        }

        public boolean supportsLocationSettingNotifications() {
            return true;
        }