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

Commit 49e030fb authored by Arthur Ishiguro's avatar Arthur Ishiguro
Browse files

Implements client close and death notification

Bug: 67734082
Test: make from root
Change-Id: Ia139fd6d4bb04c569a9ee3672e21e2700daa40a9
parent 4e39aa1e
Loading
Loading
Loading
Loading
+30 −2
Original line number Diff line number Diff line
@@ -18,12 +18,16 @@ package android.hardware.location;
import android.annotation.RequiresPermission;
import android.os.RemoteException;

import dalvik.system.CloseGuard;

import java.io.Closeable;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A class describing a client of the Context Hub Service.
 *
 * Clients can send messages to nanoapps at a Context Hub through this object.
 * Clients can send messages to nanoapps at a Context Hub through this object. The APIs supported
 * by this object are thread-safe and can be used without external synchronization.
 *
 * @hide
 */
@@ -43,12 +47,17 @@ public class ContextHubClient implements Closeable {
     */
    private final ContextHubInfo mAttachedHub;

    private final CloseGuard mCloseGuard = CloseGuard.get();

    private final AtomicBoolean mIsClosed = new AtomicBoolean(false);

    /* package */ ContextHubClient(
            IContextHubClient clientProxy, IContextHubClientCallback callback,
            ContextHubInfo hubInfo) {
        mClientProxy = clientProxy;
        mCallbackInterface = callback;
        mAttachedHub = hubInfo;
        mCloseGuard.open("close");
    }

    /**
@@ -67,7 +76,14 @@ public class ContextHubClient implements Closeable {
     * All futures messages targeted for this client are dropped at the service.
     */
    public void close() {
        throw new UnsupportedOperationException("TODO: Implement this");
        if (!mIsClosed.getAndSet(true)) {
            mCloseGuard.close();
            try {
                mClientProxy.close();
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    }

    /**
@@ -92,4 +108,16 @@ public class ContextHubClient implements Closeable {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    protected void finalize() throws Throwable {
        try {
            if (mCloseGuard != null) {
                mCloseGuard.warnIfOpen();
            }
            close();
        } finally {
            super.finalize();
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -25,4 +25,7 @@ interface IContextHubClient {

    // Sends a message to a nanoapp
    int sendMessageToNanoApp(in NanoAppMessage message);

    // Closes the connection with the Context Hub
    void close();
}
+72 −16
Original line number Diff line number Diff line
@@ -24,15 +24,21 @@ import android.hardware.location.ContextHubTransaction;
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * A broker for the ContextHubClient that handles messaging and life-cycle notification callbacks.
 * A class that acts as a broker for the ContextHubClient, which handles messaging and life-cycle
 * notification callbacks. This class implements the IContextHubClient object, and the implemented
 * APIs must be thread-safe.
 *
 * @hide
 */
public class ContextHubClientBroker extends IContextHubClient.Stub {
public class ContextHubClientBroker extends IContextHubClient.Stub
        implements IBinder.DeathRecipient {
    private static final String TAG = "ContextHubClientBroker";

    /*
@@ -45,6 +51,11 @@ public class ContextHubClientBroker extends IContextHubClient.Stub {
     */
    private final IContexthub mContextHubProxy;

    /*
     * The manager that registered this client.
     */
    private final ContextHubClientManager mClientManager;

    /*
     * The ID of the hub that this client is attached to.
     */
@@ -60,16 +71,31 @@ public class ContextHubClientBroker extends IContextHubClient.Stub {
     */
    private final IContextHubClientCallback mCallbackInterface;

    /*
     * false if the connection has been closed by the client, true otherwise.
     */
    private final AtomicBoolean mConnectionOpen = new AtomicBoolean(true);

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

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

    /**
     * Sends from this client to a nanoapp.
     *
@@ -80,10 +106,12 @@ public class ContextHubClientBroker extends IContextHubClient.Stub {
    @Override
    public int sendMessageToNanoApp(NanoAppMessage message) {
        ContextHubServiceUtil.checkPermissions(mContext);
        ContextHubMsg messageToNanoApp =
                ContextHubServiceUtil.createHidlContextHubMessage(mHostEndPointId, message);

        int result;
        if (mConnectionOpen.get()) {
            ContextHubMsg messageToNanoApp = ContextHubServiceUtil.createHidlContextHubMessage(
                    mHostEndPointId, message);

            try {
                result = mContextHubProxy.sendMessageToHub(mAttachedContextHubId, messageToNanoApp);
            } catch (RemoteException e) {
@@ -91,9 +119,35 @@ public class ContextHubClientBroker extends IContextHubClient.Stub {
                        + mAttachedContextHubId + ")", e);
                result = Result.UNKNOWN_FAILURE;
            }
        } else {
            Log.e(TAG, "Failed to send message to nanoapp: client connection is closed");
            result = Result.UNKNOWN_FAILURE;
        }

        return ContextHubServiceUtil.toTransactionResult(result);
    }

    /**
     * Closes the connection for this client with the service.
     */
    @Override
    public void close() {
        if (mConnectionOpen.getAndSet(false)) {
            mClientManager.unregisterClient(mHostEndPointId);
        }
    }

    /**
     * Invoked when the underlying binder of this broker has died at the client process.
     */
    public void binderDied() {
        try {
            IContextHubClient.Stub.asInterface(this).close();
        } catch (RemoteException e) {
            Log.e(TAG, "RemoteException while closing client on death", e);
        }
    }

    /**
     * @return the ID of the context hub this client is attached to
     */
@@ -114,6 +168,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub {
     * @param message the message that came from a nanoapp
     */
    /* package */ void sendMessageToClient(NanoAppMessage message) {
        if (mConnectionOpen.get()) {
            try {
                mCallbackInterface.onMessageFromNanoApp(message);
            } catch (RemoteException e) {
@@ -122,3 +177,4 @@ public class ContextHubClientBroker extends IContextHubClient.Stub {
            }
        }
    }
}
+28 −1
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.hardware.contexthub.V1_0.IContexthub;
import android.hardware.location.IContextHubClient;
import android.hardware.location.IContextHubClientCallback;
import android.hardware.location.NanoAppMessage;
import android.os.RemoteException;
import android.util.Log;

import java.util.NoSuchElementException;
@@ -88,6 +89,15 @@ import java.util.concurrent.ConcurrentHashMap;
            IContextHubClientCallback clientCallback, int contextHubId) {
        ContextHubClientBroker broker = createNewClientBroker(clientCallback, contextHubId);

        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;
        }

        Log.d(TAG, "Registered client with host endpoint ID " + broker.getHostEndPointId());
        return IContextHubClient.Stub.asInterface(broker);
    }
@@ -120,6 +130,23 @@ import java.util.concurrent.ConcurrentHashMap;
        }
    }

    /**
     * Unregisters a client from the service.
     *
     * This method should be invoked as a result of a client calling the ContextHubClient.close(),
     * or if the client process has died.
     *
     * @param hostEndPointId the host endpoint ID of the client that has died
     */
    /* package */ void unregisterClient(short hostEndPointId) {
        if (mHostEndPointIdToClientMap.remove(hostEndPointId) != null) {
            Log.d(TAG, "Unregistered client with host endpoint ID " + hostEndPointId);
        } else {
            Log.e(TAG, "Cannot unregister non-existing client with host endpoint ID "
                    + hostEndPointId);
        }
    }

    /**
     * Creates a new ContextHubClientBroker object for a client and registers it with the client
     * manager.
@@ -142,7 +169,7 @@ import java.util.concurrent.ConcurrentHashMap;
        for (int i = 0; i <= MAX_CLIENT_ID; i++) {
            if (!mHostEndPointIdToClientMap.containsKey(id)) {
                broker = new ContextHubClientBroker(
                        mContext, mContextHubProxy, contextHubId, (short)id, clientCallback);
                        mContext, mContextHubProxy, this, contextHubId, (short)id, clientCallback);
                mHostEndPointIdToClientMap.put((short)id, broker);
                mNextHostEndpointId = (id == MAX_CLIENT_ID) ? 0 : id + 1;
                break;