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

Commit d84c53b9 authored by Lei Ju's avatar Lei Ju
Browse files

Clean up the client when no PendingIntent exist

This change also refactors the code in a bunch of places.

Test: Presubmit

Bug: 239188851
Change-Id: I683ad404ffbd25359c795a72cc7620531d037197
parent 8a229ad0
Loading
Loading
Loading
Loading
+77 −58
Original line number Original line Diff line number Diff line
@@ -162,7 +162,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
     * The remote callback interface for this client. This will be set to null whenever the
     * The remote callback interface for this client. This will be set to null whenever the
     * client connection is closed (either explicitly or via binder death).
     * client connection is closed (either explicitly or via binder death).
     */
     */
    private IContextHubClientCallback mCallbackInterface = null;
    private IContextHubClientCallback mCallbackInterface;


    /*
    /*
     * True if the client is still registered with the Context Hub Service, false otherwise.
     * True if the client is still registered with the Context Hub Service, false otherwise.
@@ -170,16 +170,19 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    private boolean mRegistered = true;
    private boolean mRegistered = true;


    /**
    /**
     * String containing an attribution tag that was denoted in the {@link Context} of the
     * String containing an attribution tag that was denoted in the {@link Context} of the creator
     * creator of this broker. This is used when attributing the permissions usage of the broker.
     * of this broker. This is used when attributing the permissions usage of the broker.
     */
     */
    private @Nullable String mAttributionTag;
    @Nullable private String mAttributionTag;


    /** Wakelock held while nanoapp message are in flight to the client */
    /** Wakelock held while nanoapp message are in flight to the client */
    @GuardedBy("mWakeLock")
    @GuardedBy("mWakeLock")
    private final WakeLock mWakeLock;
    private final WakeLock mWakeLock;


    /** True if {@link #mWakeLock} is open for acquisition. */
    /**
     * True if {@link #mWakeLock} is open for acquisition. It is set to false after the client is
     * unregistered.
     */
    @GuardedBy("mWakeLock")
    @GuardedBy("mWakeLock")
    private boolean mIsWakeLockActive = true;
    private boolean mIsWakeLockActive = true;


@@ -223,13 +226,13 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    /*
    /*
     * True if a PendingIntent has been cancelled.
     * True if a PendingIntent has been cancelled.
     */
     */
    private AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false);
    private final AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false);


    /**
    /**
     * True if a permissions query has been issued and is being processed. Used to prevent too many
     * True if a permissions query has been issued and is being processed. Used to prevent too many
     * queries from being issued by a single client at once.
     * queries from being issued by a single client at once.
     */
     */
    private AtomicBoolean mIsPermQueryIssued = new AtomicBoolean(false);
    private final AtomicBoolean mIsPermQueryIssued = new AtomicBoolean(false);


    /*
    /*
     * Map containing all nanoapps this client has a messaging channel with and whether it is
     * Map containing all nanoapps this client has a messaging channel with and whether it is
@@ -279,7 +282,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    /*
    /*
     * Helper class to manage registered PendingIntent requests from the client.
     * Helper class to manage registered PendingIntent requests from the client.
     */
     */
    private class PendingIntentRequest {
    private static class PendingIntentRequest {
        /*
        /*
         * The PendingIntent object to request, null if there is no open request.
         * The PendingIntent object to request, null if there is no open request.
         */
         */
@@ -606,7 +609,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
     * Notifies the client of a hub reset event if the connection is open.
     * Notifies the client of a hub reset event if the connection is open.
     */
     */
    /* package */ void onHubReset() {
    /* package */ void onHubReset() {
        invokeCallback(callback -> callback.onHubReset());
        invokeCallback(IContextHubClientCallback::onHubReset);
        sendPendingIntent(() -> createIntent(ContextHubManager.EVENT_HUB_RESET));
        sendPendingIntent(() -> createIntent(ContextHubManager.EVENT_HUB_RESET));


        // Re-send the host endpoint connected event as the Context Hub restarted.
        // Re-send the host endpoint connected event as the Context Hub restarted.
@@ -634,7 +637,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
     * @return true if the given PendingIntent is currently registered, false otherwise
     * @return true if the given PendingIntent is currently registered, false otherwise
     */
     */
    /* package */ boolean hasPendingIntent(PendingIntent intent, long nanoAppId) {
    /* package */ boolean hasPendingIntent(PendingIntent intent, long nanoAppId) {
        PendingIntent pendingIntent = null;
        PendingIntent pendingIntent;
        long intentNanoAppId;
        long intentNanoAppId;
        synchronized (this) {
        synchronized (this) {
            pendingIntent = mPendingIntentRequest.getPendingIntent();
            pendingIntent = mPendingIntentRequest.getPendingIntent();
@@ -680,7 +683,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
     */
     */
    /* package */ boolean notePermissions(List<String> permissions, String noteMessage) {
    /* package */ boolean notePermissions(List<String> permissions, String noteMessage) {
        for (String permission : permissions) {
        for (String permission : permissions) {
            int opCode = mAppOpsManager.permissionToOpCode(permission);
            int opCode = AppOpsManager.permissionToOpCode(permission);
            if (opCode != AppOpsManager.OP_NONE) {
            if (opCode != AppOpsManager.OP_NONE) {
                try {
                try {
                    if (mAppOpsManager.noteOp(opCode, mUid, mPackage, mAttributionTag, noteMessage)
                    if (mAppOpsManager.noteOp(opCode, mUid, mPackage, mAttributionTag, noteMessage)
@@ -833,7 +836,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    private synchronized void invokeCallback(CallbackConsumer consumer) {
    private synchronized void invokeCallback(CallbackConsumer consumer) {
        if (mCallbackInterface != null) {
        if (mCallbackInterface != null) {
            try {
            try {
                Binder.withCleanCallingIdentity(this::acquireWakeLock);
                acquireWakeLock();
                consumer.accept(mCallbackInterface);
                consumer.accept(mCallbackInterface);
            } catch (RemoteException e) {
            } catch (RemoteException e) {
                Log.e(TAG, "RemoteException while invoking client callback (host endpoint ID = "
                Log.e(TAG, "RemoteException while invoking client callback (host endpoint ID = "
@@ -902,7 +905,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
    private void doSendPendingIntent(PendingIntent pendingIntent, Intent intent) {
    private void doSendPendingIntent(PendingIntent pendingIntent, Intent intent) {
        try {
        try {
            String requiredPermission = Manifest.permission.ACCESS_CONTEXT_HUB;
            String requiredPermission = Manifest.permission.ACCESS_CONTEXT_HUB;
            Binder.withCleanCallingIdentity(this::acquireWakeLock);
            acquireWakeLock();
            pendingIntent.send(
            pendingIntent.send(
                    mContext,
                    mContext,
                    /* code= */ 0,
                    /* code= */ 0,
@@ -939,13 +942,14 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
            mCallbackInterface.asBinder().unlinkToDeath(this, 0 /* flags */);
            mCallbackInterface.asBinder().unlinkToDeath(this, 0 /* flags */);
            mCallbackInterface = null;
            mCallbackInterface = null;
        }
        }
        // The client is only unregistered and cleared when there is NOT any PendingIntent
        if (!mPendingIntentRequest.hasPendingIntent() && mRegistered) {
        if (!mPendingIntentRequest.hasPendingIntent() && mRegistered) {
            mClientManager.unregisterClient(mHostEndPointId);
            mClientManager.unregisterClient(mHostEndPointId);
            mRegistered = false;
            mRegistered = false;
            Binder.withCleanCallingIdentity(this::releaseWakeLockOnExit);
        }
            mAppOpsManager.stopWatchingMode(this);
            mAppOpsManager.stopWatchingMode(this);
            mContextHubProxy.onHostEndpointDisconnected(mHostEndPointId);
            mContextHubProxy.onHostEndpointDisconnected(mHostEndPointId);
            releaseWakeLockOnExit();
        }
    }
    }


    private String authStateToString(@ContextHubManager.AuthorizationState int state) {
    private String authStateToString(@ContextHubManager.AuthorizationState int state) {
@@ -996,43 +1000,46 @@ public class ContextHubClientBroker extends IContextHubClient.Stub


    @Override
    @Override
    public String toString() {
    public String toString() {
        String out = "[ContextHubClient ";
        StringBuilder out = new StringBuilder("[ContextHubClient ");
        out += "endpointID: " + getHostEndPointId() + ", ";
        out.append("endpointID: ").append(getHostEndPointId()).append(", ");
        out += "contextHub: " + getAttachedContextHubId() + ", ";
        out.append("contextHub: ").append(getAttachedContextHubId()).append(", ");
        if (mAttributionTag != null) {
        if (mAttributionTag != null) {
            out += "attributionTag: " + getAttributionTag() + ", ";
            out.append("attributionTag: ").append(getAttributionTag()).append(", ");
        }
        }
        if (mPendingIntentRequest.isValid()) {
        if (mPendingIntentRequest.isValid()) {
            out += "intentCreatorPackage: " + mPackage + ", ";
            out.append("intentCreatorPackage: ").append(mPackage).append(", ");
            out += "nanoAppId: 0x" + Long.toHexString(mPendingIntentRequest.getNanoAppId());
            out.append("nanoAppId: 0x")
                    .append(Long.toHexString(mPendingIntentRequest.getNanoAppId()));
        } else {
        } else {
            out += "package: " + mPackage;
            out.append("package: ").append(mPackage);
        }
        }
        if (mMessageChannelNanoappIdMap.size() > 0) {
        if (mMessageChannelNanoappIdMap.size() > 0) {
            out += " messageChannelNanoappSet: (";
            out.append(" messageChannelNanoappSet: (");
            Iterator<Map.Entry<Long, Integer>> it =
            Iterator<Map.Entry<Long, Integer>> it =
                    mMessageChannelNanoappIdMap.entrySet().iterator();
                    mMessageChannelNanoappIdMap.entrySet().iterator();
            while (it.hasNext()) {
            while (it.hasNext()) {
                Map.Entry<Long, Integer> entry = it.next();
                Map.Entry<Long, Integer> entry = it.next();
                out += "0x" + Long.toHexString(entry.getKey()) + " auth state: "
                out.append("0x")
                        + authStateToString(entry.getValue());
                        .append(Long.toHexString(entry.getKey()))
                        .append(" auth state: ")
                        .append(authStateToString(entry.getValue()));
                if (it.hasNext()) {
                if (it.hasNext()) {
                    out += ",";
                    out.append(",");
                }
                }
            }
            }
            out += ")";
            out.append(")");
        }
        }
        synchronized (mWakeLock) {
        synchronized (mWakeLock) {
            out += "wakelock: " + mWakeLock;
            out.append("wakelock: ").append(mWakeLock);
        }
        }
        out += "]";
        out.append("]");
        return out;
        return out.toString();
    }
    }


    /** Callback that arrives when direct-call message callback delivery completed */
    /** Callback that arrives when direct-call message callback delivery completed */
    @Override
    @Override
    public void callbackFinished() {
    public void callbackFinished() {
        Binder.withCleanCallingIdentity(this::releaseWakeLock);
        releaseWakeLock();
    }
    }


    @Override
    @Override
@@ -1042,15 +1049,18 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
            int resultCode,
            int resultCode,
            String resultData,
            String resultData,
            Bundle resultExtras) {
            Bundle resultExtras) {
        Binder.withCleanCallingIdentity(this::releaseWakeLock);
        releaseWakeLock();
    }
    }


    private void acquireWakeLock() {
    private void acquireWakeLock() {
        Binder.withCleanCallingIdentity(
                () -> {
                    synchronized (mWakeLock) {
                    synchronized (mWakeLock) {
                        if (mIsWakeLockActive) {
                        if (mIsWakeLockActive) {
                            mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
                            mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
                        }
                        }
                    }
                    }
                });
    }
    }


    /**
    /**
@@ -1059,6 +1069,8 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
     * <p>The check-and-release operation should be atomic to avoid overly release.
     * <p>The check-and-release operation should be atomic to avoid overly release.
     */
     */
    private void releaseWakeLock() {
    private void releaseWakeLock() {
        Binder.withCleanCallingIdentity(
                () -> {
                    synchronized (mWakeLock) {
                    synchronized (mWakeLock) {
                        if (mWakeLock.isHeld()) {
                        if (mWakeLock.isHeld()) {
                            try {
                            try {
@@ -1068,6 +1080,7 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
                            }
                            }
                        }
                        }
                    }
                    }
                });
    }
    }


    /**
    /**
@@ -1076,16 +1089,22 @@ public class ContextHubClientBroker extends IContextHubClient.Stub
     * <p>The check-and-release operation should be atomic to avoid overly release.
     * <p>The check-and-release operation should be atomic to avoid overly release.
     */
     */
    private void releaseWakeLockOnExit() {
    private void releaseWakeLockOnExit() {
        Binder.withCleanCallingIdentity(
                () -> {
                    synchronized (mWakeLock) {
                    synchronized (mWakeLock) {
                        mIsWakeLockActive = false;
                        mIsWakeLockActive = false;
                        while (mWakeLock.isHeld()) {
                        while (mWakeLock.isHeld()) {
                            try {
                            try {
                                mWakeLock.release();
                                mWakeLock.release();
                            } catch (RuntimeException e) {
                            } catch (RuntimeException e) {
                    Log.e(TAG, "Releasing the wakelock for all acquisitions fails - ", e);
                                Log.e(
                                        TAG,
                                        "Releasing the wakelock for all acquisitions fails - ",
                                        e);
                                break;
                                break;
                            }
                            }
                        }
                        }
                    }
                    }
                });
    }
    }
}
}