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

Commit 3685d314 authored by Arthur Ishiguro's avatar Arthur Ishiguro Committed by Android (Google) Code Review
Browse files

Merge changes I9f2d4e1b,Iad9ada1f,Ic8d269b4

* changes:
  Implements PendingIntent based createClient API
  Adds bindClient method to service AIDL
  Close unregistered clients with no PendingIntent
parents 891aa9ed 6cc24a5d
Loading
Loading
Loading
Loading
+20 −4
Original line number Diff line number Diff line
@@ -808,7 +808,7 @@ public final class ContextHubManager {
     *
     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
     *                                  was not associated with a client
     * @throws IllegalStateException    if there were too many registered clients at the service
     * @throws IllegalStateException    if the client is already registered to a valid callback
     * @throws NullPointerException     if pendingIntent, hubInfo, callback, or executor is null
     *
     * @hide
@@ -818,8 +818,24 @@ public final class ContextHubManager {
            @NonNull PendingIntent pendingIntent, @NonNull ContextHubInfo hubInfo,
            @NonNull ContextHubClientCallback callback,
            @NonNull @CallbackExecutor Executor executor) {
        // TODO: Implement this
        throw new UnsupportedOperationException("Not implemented yet");
        Preconditions.checkNotNull(pendingIntent, "PendingIntent cannot be null");
        Preconditions.checkNotNull(callback, "Callback cannot be null");
        Preconditions.checkNotNull(hubInfo, "ContextHubInfo cannot be null");
        Preconditions.checkNotNull(executor, "Executor cannot be null");

        ContextHubClient client = new ContextHubClient(hubInfo);
        IContextHubClientCallback clientInterface = createClientCallback(
                client, callback, executor);

        IContextHubClient clientProxy;
        try {
            clientProxy = mService.bindClient(pendingIntent, clientInterface, hubInfo.getId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }

        client.setClientProxy(clientProxy);
        return client;
    }

    /**
@@ -833,7 +849,7 @@ public final class ContextHubManager {
     *
     * @throws IllegalArgumentException if hubInfo does not represent a valid hub, or pendingIntent
     *                                  was not associated with a client
     * @throws IllegalStateException    if there were too many registered clients at the service
     * @throws IllegalStateException    if the client is already registered to a valid callback
     * @throws NullPointerException     if pendingIntent, hubInfo, or callback is null
     *
     * @hide
+6 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.hardware.location;

// Declare any non-default types here with import statements
import android.app.PendingIntent;
import android.hardware.location.ContextHubInfo;
import android.hardware.location.ContextHubMessage;
import android.hardware.location.NanoApp;
@@ -60,6 +61,11 @@ interface IContextHubService {
    // Creates a client to send and receive messages
    IContextHubClient createClient(in IContextHubClientCallback client, int contextHubId);

    // Binds an existing client to a new callback interface, provided a previously registered
    // PendingIntent
    IContextHubClient bindClient(
            in PendingIntent pendingIntent, in IContextHubClientCallback client, int contextHubId);

    // Returns a list of ContextHub objects of available hubs
    List<ContextHubInfo> getContextHubs();

+54 −15
Original line number Diff line number Diff line
@@ -159,25 +159,12 @@ public class ContextHubClientBroker extends IContextHubClient.Stub

    /* package */ ContextHubClientBroker(
            Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
            ContextHubInfo contextHubInfo, short hostEndPointId,
            IContextHubClientCallback callback) {
            ContextHubInfo contextHubInfo, short hostEndPointId) {
        mContext = context;
        mContextHubProxy = contextHubProxy;
        mClientManager = clientManager;
        mAttachedContextHubInfo = contextHubInfo;
        mHostEndPointId = hostEndPointId;
        mCallbackInterface = callback;
    }

    /**
     * Attaches a death recipient for this client
     *
     * @throws RemoteException if the client has already died
     */
    /* package */ synchronized void attachDeathRecipient() throws RemoteException {
        if (mCallbackInterface != null) {
            mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
        }
    }

    /**
@@ -245,9 +232,15 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    public boolean unregisterIntent(PendingIntent pendingIntent) {
        ContextHubServiceUtil.checkPermissions(mContext);

        boolean success = false;
        synchronized (this) {
            return mPendingIntentRequest.unregister(pendingIntent);
            success = mPendingIntentRequest.unregister(pendingIntent);
            if (mCallbackInterface == null) {
                close();
            }
        }

        return success;
    }

    /**
@@ -275,6 +268,37 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
        close();
    }

    /**
     * Sets the callback interface for this client, only if the callback is currently unregistered.
     *
     * Also attaches a death recipient to a ContextHubClientBroker object. If unsuccessful, the
     * connection is closed.
     *
     * @param callback the callback interface
     * @return true if the callback was successfully set, false otherwise
     *
     * @throws IllegalStateException if the client has already been registered to a callback
     */
    /* package */
    synchronized boolean setCallback(IContextHubClientCallback callback) {
        boolean success = false;
        if (mCallbackInterface != null) {
            throw new IllegalStateException("Client is already registered with a callback");
        } else {
            mCallbackInterface = callback;
            try {
                mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
                success = true;
            } catch (RemoteException e) {
                // The client process has died, so we close the connection.
                Log.e(TAG, "Failed to attach death recipient to client");
                close();
            }
        }

        return success;
    }

    /**
     * @return the ID of the context hub this client is attached to
     */
@@ -346,6 +370,18 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
        sendPendingIntent(supplier);
    }

    /**
     * @param intent the PendingIntent to compare to
     * @return true if the given PendingIntent is currently registered, false otherwise
     */
    /* package */ boolean hasPendingIntent(PendingIntent intent) {
        PendingIntent pendingIntent = null;
        synchronized (this) {
            pendingIntent = mPendingIntentRequest.getPendingIntent();
        }
        return (pendingIntent != null) && pendingIntent.equals(intent);
    }

    /**
     * Helper function to invoke a specified client callback, if the connection is open.
     *
@@ -407,6 +443,9 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
                Log.w(TAG, "PendingIntent has been canceled, unregistering from client"
                        + " (host endpoint ID " + mHostEndPointId + ")");
                mPendingIntentRequest.clear();
                if (mCallbackInterface == null) {
                    close();
                }
            }
        }
    }
+54 −13
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.location;

import android.app.PendingIntent;
import android.content.Context;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.IContexthub;
@@ -88,21 +89,45 @@ import java.util.function.Consumer;
     */
    /* package */ IContextHubClient registerClient(
            IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
        ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubInfo);

        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");
            broker.close();
            return null;
        ContextHubClientBroker broker = createNewClientBroker(contextHubInfo);
        if (!broker.setCallback(clientCallback)) {
            return null; // Client process has died, so we return null
        }

        Log.d(TAG, "Registered client with host endpoint ID " + broker.getHostEndPointId());
        return IContextHubClient.Stub.asInterface(broker);
    }

    /**
     * Binds a existing and registered client with a new callback interface, provided a previously
     * registered PendingIntent.
     *
     * @param pendingIntent  a previously registered PendingIntent for a registered client
     * @param clientCallback the callback interface of the client to bind to
     * @param contextHubId   the ID of the hub this client is attached to
     *
     * @return the client interface
     *
     * @throws IllegalArgumentException if no matching client is found
     * @throws IllegalStateException    if the client has already been registered to a callback
     */
    /* package */ IContextHubClient bindClient(
            PendingIntent pendingIntent, IContextHubClientCallback clientCallback,
            int contextHubId) {
        ContextHubClientBroker broker = getClientBroker(pendingIntent, contextHubId);
        if (broker == null) {
            throw new IllegalArgumentException("Could not find client of Context Hub (ID = "
                    + contextHubId + ") with PendingIntent");
        }

        if (!broker.setCallback(clientCallback)) {
            return null; // Client process has died, so we return null
        }

        Log.d(TAG, "Re-registered client with host endpoint ID " + broker.getHostEndPointId());
        return IContextHubClient.Stub.asInterface(broker);
    }

    /**
     * Handles a message sent from a nanoapp.
     *
@@ -182,7 +207,6 @@ import java.util.function.Consumer;
     * Creates a new ContextHubClientBroker object for a client and registers it with the client
     * manager.
     *
     * @param clientCallback the callback interface of the client to register
     * @param contextHubInfo the object describing the hub this client is attached to
     *
     * @return the ContextHubClientBroker object
@@ -190,7 +214,7 @@ import java.util.function.Consumer;
     * @throws IllegalStateException if max number of clients have already registered
     */
    private synchronized ContextHubClientBroker createNewClientBroker(
            IContextHubClientCallback clientCallback, ContextHubInfo contextHubInfo) {
            ContextHubInfo contextHubInfo) {
        if (mHostEndPointIdToClientMap.size() == MAX_CLIENT_ID + 1) {
            throw new IllegalStateException("Could not register client - max limit exceeded");
        }
@@ -200,8 +224,7 @@ import java.util.function.Consumer;
        for (int i = 0; i <= MAX_CLIENT_ID; i++) {
            if (!mHostEndPointIdToClientMap.containsKey((short) id)) {
                broker = new ContextHubClientBroker(
                        mContext, mContextHubProxy, this, contextHubInfo, (short) id,
                        clientCallback);
                        mContext, mContextHubProxy, this, contextHubInfo, (short) id);
                mHostEndPointIdToClientMap.put((short) id, broker);
                mNextHostEndpointId = (id == MAX_CLIENT_ID) ? 0 : id + 1;
                break;
@@ -236,4 +259,22 @@ import java.util.function.Consumer;
            }
        }
    }

    /**
     * Retrieves a ContextHubClientBroker object with a matching PendingIntent and Context Hub ID.
     *
     * @param pendingIntent the PendingIntent to match
     * @param contextHubId  the ID of the Context Hub the client is attached to
     * @return the matching ContextHubClientBroker, null if not found
     */
    private ContextHubClientBroker getClientBroker(PendingIntent pendingIntent, int contextHubId) {
        for (ContextHubClientBroker broker : mHostEndPointIdToClientMap.values()) {
            if (broker.hasPendingIntent(pendingIntent)
                    && broker.getAttachedContextHubId() == contextHubId) {
                return broker;
            }
        }

        return null;
    }
}
+32 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.server.location;

import android.app.PendingIntent;
import android.content.Context;
import android.hardware.contexthub.V1_0.AsyncEventType;
import android.hardware.contexthub.V1_0.ContextHub;
@@ -630,6 +631,37 @@ public class ContextHubService extends IContextHubService.Stub {
        return mClientManager.registerClient(clientCallback, contextHubInfo);
    }

    /**
     * Recreates and binds a IContextHubClientCallback interface to an existing and registered
     * client at the service for the specified Context Hub, provided a previously registered
     * PendingIntent.
     *
     * @param pendingIntent  the PendingIntent previously registered for the client
     * @param clientCallback the client interface to register with the service
     * @param contextHubId   the ID of the hub this client is attached to
     * @return the generated client interface, null if registration was unsuccessful
     *
     * @throws IllegalArgumentException if contextHubId is not a valid ID
     * @throws NullPointerException if clientCallback or pendingIntent is null
     */
    @Override
    public IContextHubClient bindClient(
            PendingIntent pendingIntent, IContextHubClientCallback clientCallback,
            int contextHubId) throws RemoteException {
        checkPermissions();
        if (!isValidContextHubId(contextHubId)) {
            throw new IllegalArgumentException("Invalid context hub ID " + contextHubId);
        }
        if (pendingIntent == null) {
            throw new NullPointerException("Cannot create client with null pending intent");
        }
        if (clientCallback == null) {
            throw new NullPointerException("Cannot create client with null callback");
        }

        return mClientManager.bindClient(pendingIntent, clientCallback, contextHubId);
    }

    /**
     * Loads a nanoapp binary at the specified Context hub.
     *