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

Commit 6fbfc191 authored by Matthew Sedam's avatar Matthew Sedam
Browse files

Add death recipient for Context Hub AIDL HAL

When the Context Hub AIDL HAL dies, we need to reconnect to the
binder interface and reset the Context Hub Service.

Bug: 246384988
Test: m && ./vendor/google/tools/flashall
Test: adb shell dumpsys contexthub # normal
Test: adb shell logcat | grep -iE 'CHRE|contexthub' # normal
Test: kill AIDL HAL process # Context Hub restarts
Test: Run CHQTS tests before and after AIDL HAL death
Test: Same tests passed
Change-Id: I86d4c87a3b8f6aa4c476fbc866432400ba7f4a3b
parent 96ca8869
Loading
Loading
Loading
Loading
+34 −5
Original line number Diff line number Diff line
@@ -207,6 +207,14 @@ public class ContextHubService extends IContextHubService.Stub {
            handleClientMessageCallback(mContextHubId, hostEndpointId, message, nanoappPermissions,
                    messagePermissions);
        }

        @Override
        public void handleServiceRestart() {
            Log.i(TAG, "Starting Context Hub Service restart");
            initExistingCallbacks();
            resetSettings();
            Log.i(TAG, "Finished Context Hub Service restart");
        }
    }

    public ContextHubService(Context context, IContextHubWrapper contextHubWrapper) {
@@ -380,6 +388,20 @@ public class ContextHubService extends IContextHubService.Stub {
        mDefaultClientMap = Collections.unmodifiableMap(defaultClientMap);
    }

    /**
     * Initializes existing callbacks with the mContextHubWrapper for every context hub
     */
    private void initExistingCallbacks() {
        for (int contextHubId : mContextHubIdToInfoMap.keySet()) {
            try {
                mContextHubWrapper.registerExistingCallback(contextHubId);
            } catch (RemoteException e) {
                Log.e(TAG, "RemoteException while registering existing service callback for hub "
                        + "(ID = " + contextHubId + ")", e);
            }
        }
    }

    /**
     * Handles the initialization of location settings notifications
     */
@@ -508,6 +530,17 @@ public class ContextHubService extends IContextHubService.Stub {
        mContext.registerReceiver(btReceiver, filter);
    }

    /**
     * Resets the settings. Called when a context hub restarts or the AIDL HAL dies
     */
    private void resetSettings() {
        sendLocationSettingUpdate();
        sendWifiSettingUpdate(/* forceUpdate= */ true);
        sendAirplaneModeSettingUpdate();
        sendMicrophoneDisableSettingUpdateForCurrentUser();
        sendBtSettingUpdate(/* forceUpdate= */ true);
    }

    @Override
    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
            String[] args, ShellCallback callback, ResultReceiver result) {
@@ -841,11 +874,7 @@ public class ContextHubService extends IContextHubService.Stub {

            ContextHubEventLogger.getInstance().logContextHubRestart(contextHubId);

            sendLocationSettingUpdate();
            sendWifiSettingUpdate(/* forceUpdate= */ true);
            sendAirplaneModeSettingUpdate();
            sendMicrophoneDisableSettingUpdateForCurrentUser();
            sendBtSettingUpdate(/* forceUpdate= */ true);
            resetSettings();

            mTransactionManager.onHubReset();
            queryNanoAppsInternal(contextHubId);
+174 −23
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.hardware.location.NanoAppMessage;
import android.hardware.location.NanoAppState;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -92,6 +93,11 @@ public abstract class IContextHubWrapper {
         */
        void handleNanoappMessage(short hostEndpointId, NanoAppMessage message,
                List<String> nanoappPermissions, List<String> messagePermissions);

        /**
         * Handles a restart of the service
         */
        void handleServiceRestart();
    }

    /**
@@ -170,12 +176,9 @@ public abstract class IContextHubWrapper {
    }

    /**
     * Attempts to connect to the Contexthub HAL AIDL service, if it exists.
     *
     * @return A valid IContextHubWrapper if the connection was successful, null otherwise.
     * Attempts to connect to the AIDL HAL and returns the proxy IContextHub.
     */
    @Nullable
    public static IContextHubWrapper maybeConnectToAidl() {
    public static android.hardware.contexthub.IContextHub maybeConnectToAidlGetProxy() {
        android.hardware.contexthub.IContextHub proxy = null;
        final String aidlServiceName =
                android.hardware.contexthub.IContextHub.class.getCanonicalName() + "/default";
@@ -188,8 +191,18 @@ public abstract class IContextHubWrapper {
        } else {
            Log.d(TAG, "Context Hub AIDL service is not declared");
        }
        return proxy;
    }

        return (proxy == null) ? null : new ContextHubWrapperAidl(proxy);
    /**
     * Attempts to connect to the Contexthub HAL AIDL service, if it exists.
     *
     * @return A valid IContextHubWrapper if the connection was successful, null otherwise.
     */
    @Nullable
    public static IContextHubWrapper maybeConnectToAidl() {
        android.hardware.contexthub.IContextHub proxy = maybeConnectToAidlGetProxy();
        return proxy == null ? null : new ContextHubWrapperAidl(proxy);
    }

    /**
@@ -354,12 +367,22 @@ public abstract class IContextHubWrapper {
    public abstract void registerCallback(int contextHubId, @NonNull ICallback callback)
            throws RemoteException;

    private static class ContextHubWrapperAidl extends IContextHubWrapper {
    /**
     * Registers an existing callback with the Context Hub.
     *
     * @param contextHubId The ID of the Context Hub to register the callback with.
     */
    public abstract void registerExistingCallback(int contextHubId) throws RemoteException;

    private static class ContextHubWrapperAidl extends IContextHubWrapper
            implements IBinder.DeathRecipient {
        private android.hardware.contexthub.IContextHub mHub;

        private final Map<Integer, ContextHubAidlCallback> mAidlCallbackMap =
                    new HashMap<>();

        private Runnable mHandleServiceRestartCallback = null;

        // Use this thread in case where the execution requires to be on a service thread.
        // For instance, AppOpsManager.noteOp requires the UPDATE_APP_OPS_STATS permission.
        private HandlerThread mHandlerThread =
@@ -419,17 +442,51 @@ public abstract class IContextHubWrapper {
        }

        ContextHubWrapperAidl(android.hardware.contexthub.IContextHub hub) {
            mHub = hub;
            setHub(hub);
            mHandlerThread.start();
            mHandler = new Handler(mHandlerThread.getLooper());
            linkWrapperToHubDeath();
        }

        private synchronized android.hardware.contexthub.IContextHub getHub() {
            return mHub;
        }

        private synchronized void setHub(android.hardware.contexthub.IContextHub hub) {
            mHub = hub;
        }

        @Override
        public void binderDied() {
            Log.i(TAG, "Context Hub AIDL HAL died");

            setHub(maybeConnectToAidlGetProxy());
            if (getHub() == null) {
                // TODO(b/256860015): Make this reconnection more robust
                Log.e(TAG, "Could not reconnect to Context Hub AIDL HAL");
                return;
            }
            linkWrapperToHubDeath();

            if (mHandleServiceRestartCallback != null) {
                mHandleServiceRestartCallback.run();
            } else {
                Log.e(TAG, "mHandleServiceRestartCallback is not set");
            }
        }

        public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return new Pair<List<ContextHubInfo>, List<String>>(new ArrayList<ContextHubInfo>(),
                        new ArrayList<String>());
            }

            Set<String> supportedPermissions = new HashSet<>();
            ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
            for (android.hardware.contexthub.ContextHubInfo hub : mHub.getContextHubs()) {
                hubInfoList.add(new ContextHubInfo(hub));
                for (String permission : hub.supportedPermissions) {
            for (android.hardware.contexthub.ContextHubInfo hubInfo : hub.getContextHubs()) {
                hubInfoList.add(new ContextHubInfo(hubInfo));
                for (String permission : hubInfo.supportedPermissions) {
                    supportedPermissions.add(permission);
                }
            }
@@ -489,8 +546,13 @@ public abstract class IContextHubWrapper {

        @Override
        public void onHostEndpointConnected(HostEndpointInfo info) {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }

            try {
                mHub.onHostEndpointConnected(info);
                hub.onHostEndpointConnected(info);
            } catch (RemoteException | ServiceSpecificException e) {
                Log.e(TAG, "Exception in onHostEndpointConnected" + e.getMessage());
            }
@@ -498,8 +560,13 @@ public abstract class IContextHubWrapper {

        @Override
        public void onHostEndpointDisconnected(short hostEndpointId) {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }

            try {
                mHub.onHostEndpointDisconnected((char) hostEndpointId);
                hub.onHostEndpointDisconnected((char) hostEndpointId);
            } catch (RemoteException | ServiceSpecificException e) {
                Log.e(TAG, "Exception in onHostEndpointDisconnected" + e.getMessage());
            }
@@ -509,8 +576,13 @@ public abstract class IContextHubWrapper {
        public int sendMessageToContextHub(
                short hostEndpointId, int contextHubId, NanoAppMessage message)
                throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
            }

            try {
                mHub.sendMessageToHub(contextHubId,
                hub.sendMessageToHub(contextHubId,
                        ContextHubServiceUtil.createAidlContextHubMessage(hostEndpointId, message));
                return ContextHubTransaction.RESULT_SUCCESS;
            } catch (RemoteException | ServiceSpecificException e) {
@@ -523,10 +595,15 @@ public abstract class IContextHubWrapper {
        @ContextHubTransaction.Result
        public int loadNanoapp(int contextHubId, NanoAppBinary binary,
                int transactionId) throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
            }

            android.hardware.contexthub.NanoappBinary aidlNanoAppBinary =
                    ContextHubServiceUtil.createAidlNanoAppBinary(binary);
            try {
                mHub.loadNanoapp(contextHubId, aidlNanoAppBinary, transactionId);
                hub.loadNanoapp(contextHubId, aidlNanoAppBinary, transactionId);
                return ContextHubTransaction.RESULT_SUCCESS;
            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
@@ -538,8 +615,13 @@ public abstract class IContextHubWrapper {
        @ContextHubTransaction.Result
        public int unloadNanoapp(int contextHubId, long nanoappId, int transactionId)
                throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
            }

            try {
                mHub.unloadNanoapp(contextHubId, nanoappId, transactionId);
                hub.unloadNanoapp(contextHubId, nanoappId, transactionId);
                return ContextHubTransaction.RESULT_SUCCESS;
            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
@@ -551,8 +633,13 @@ public abstract class IContextHubWrapper {
        @ContextHubTransaction.Result
        public int enableNanoapp(int contextHubId, long nanoappId, int transactionId)
                throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
            }

            try {
                mHub.enableNanoapp(contextHubId, nanoappId, transactionId);
                hub.enableNanoapp(contextHubId, nanoappId, transactionId);
                return ContextHubTransaction.RESULT_SUCCESS;
            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
@@ -564,8 +651,13 @@ public abstract class IContextHubWrapper {
        @ContextHubTransaction.Result
        public int disableNanoapp(int contextHubId, long nanoappId, int transactionId)
                throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
            }

            try {
                mHub.disableNanoapp(contextHubId, nanoappId, transactionId);
                hub.disableNanoapp(contextHubId, nanoappId, transactionId);
                return ContextHubTransaction.RESULT_SUCCESS;
            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
@@ -576,8 +668,13 @@ public abstract class IContextHubWrapper {

        @ContextHubTransaction.Result
        public int queryNanoapps(int contextHubId) throws RemoteException {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS;
            }

            try {
                mHub.queryNanoapps(contextHubId);
                hub.queryNanoapps(contextHubId);
                return ContextHubTransaction.RESULT_SUCCESS;
            } catch (RemoteException | ServiceSpecificException | UnsupportedOperationException e) {
                return ContextHubTransaction.RESULT_FAILED_UNKNOWN;
@@ -586,22 +683,65 @@ public abstract class IContextHubWrapper {
            }
        }

        public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
            mAidlCallbackMap.put(contextHubId, new ContextHubAidlCallback(contextHubId, callback));
        public void registerExistingCallback(int contextHubId) {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }

            ContextHubAidlCallback callback = mAidlCallbackMap.get(contextHubId);
            if (callback == null) {
                Log.e(TAG, "Could not find existing callback to register for context hub ID = "
                        + contextHubId);
                return;
            }

            try {
                mHub.registerCallback(contextHubId, mAidlCallbackMap.get(contextHubId));
                hub.registerCallback(contextHubId, callback);
            } catch (RemoteException | ServiceSpecificException | IllegalArgumentException e) {
                Log.e(TAG, "Exception while registering callback: " + e.getMessage());
            }
        }

        public void registerCallback(int contextHubId, ICallback callback) {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }

            mHandleServiceRestartCallback = callback::handleServiceRestart;
            mAidlCallbackMap.put(contextHubId, new ContextHubAidlCallback(contextHubId, callback));
            registerExistingCallback(contextHubId);
        }

        private void onSettingChanged(byte setting, boolean enabled) {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }

            try {
                mHub.onSettingChanged(setting, enabled);
                hub.onSettingChanged(setting, enabled);
            } catch (RemoteException | ServiceSpecificException e) {
                Log.e(TAG, "Exception while sending setting update: " + e.getMessage());
            }
        }

        /**
         * Links the mHub death handler to this
         */
        private void linkWrapperToHubDeath() {
            android.hardware.contexthub.IContextHub hub = getHub();
            if (hub == null) {
                return;
            }

            try {
                hub.asBinder().linkToDeath(this, 0);
            } catch (RemoteException exception) {
                Log.e(TAG, "Context Hub AIDL service death receipt could not be linked");
            }
        }
    }

    /**
@@ -729,6 +869,17 @@ public abstract class IContextHubWrapper {
            mHub.registerCallback(contextHubId, mHidlCallbackMap.get(contextHubId));
        }

        public void registerExistingCallback(int contextHubId) throws RemoteException {
            ContextHubWrapperHidlCallback callback = mHidlCallbackMap.get(contextHubId);
            if (callback == null) {
                Log.e(TAG, "Could not find existing callback for context hub with ID = "
                        + contextHubId);
                return;
            }

            mHub.registerCallback(contextHubId, callback);
        }

        public boolean supportsBtSettingNotifications() {
            return false;
        }