From 6fbfc19179161aebd922943bc2fb6de3a400be03 Mon Sep 17 00:00:00 2001 From: Matthew Sedam Date: Thu, 6 Oct 2022 21:10:28 +0000 Subject: 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 --- .../location/contexthub/ContextHubService.java | 39 +++- .../location/contexthub/IContextHubWrapper.java | 197 ++++++++++++++++++--- 2 files changed, 208 insertions(+), 28 deletions(-) diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java index 6232028bbabe..4eef147b40c5 100644 --- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java +++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java @@ -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); diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java index 432b097afe83..48152b40aaf6 100644 --- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java +++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java @@ -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 nanoappPermissions, List 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 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> getHubs() throws RemoteException { + android.hardware.contexthub.IContextHub hub = getHub(); + if (hub == null) { + return new Pair, List>(new ArrayList(), + new ArrayList()); + } + Set supportedPermissions = new HashSet<>(); ArrayList 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; } -- cgit v1.2.3-59-g8ed1b