Framework changes for Context Hub AIDL

Bug: 194285834
Test: Load on device
Change-Id: I3a0ffa7f3e8af0fa0d127f2e7176c3b0228ef989
diff --git a/Android.bp b/Android.bp
index 9127966f..0ac41c0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -238,6 +238,7 @@
         "android.hardware.contexthub-V1.0-java",
         "android.hardware.contexthub-V1.1-java",
         "android.hardware.contexthub-V1.2-java",
+        "android.hardware.contexthub-V1-java",
         "android.hardware.gnss-V1.0-java",
         "android.hardware.gnss-V2.1-java",
         "android.hardware.health-V1.0-java-constants",
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index 6d56d2d..51045a4 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -79,6 +79,29 @@
         mSupportedSensors = new int[0];
         mMemoryRegions = new MemoryRegion[0];
     }
+    /**
+     * @hide
+     */
+    public ContextHubInfo(android.hardware.contexthub.ContextHubInfo contextHub) {
+        mId = contextHub.id;
+        mName = contextHub.name;
+        mVendor = contextHub.vendor;
+        mToolchain = contextHub.toolchain;
+        mPlatformVersion = 0;
+        mToolchainVersion = 0;
+        mPeakMips = contextHub.peakMips;
+        mStoppedPowerDrawMw = 0;
+        mSleepPowerDrawMw = 0;
+        mPeakPowerDrawMw = 0;
+        mMaxPacketLengthBytes = contextHub.maxSupportedMessageLengthBytes;
+        mChrePlatformId = contextHub.chrePlatformId;
+        mChreApiMajorVersion = contextHub.chreApiMajorVersion;
+        mChreApiMinorVersion = contextHub.chreApiMinorVersion;
+        mChrePatchVersion = (short) contextHub.chrePatchVersion;
+
+        mSupportedSensors = new int[0];
+        mMemoryRegions = new MemoryRegion[0];
+    }
 
     /**
      * returns the maximum number of bytes that can be sent per message to the hub
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 27a78dd..a491eb7 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -359,7 +359,10 @@
      * @return the IContextHubWrapper interface
      */
     private IContextHubWrapper getContextHubWrapper() {
-        IContextHubWrapper wrapper = IContextHubWrapper.maybeConnectTo1_2();
+        IContextHubWrapper wrapper = IContextHubWrapper.maybeConnectToAidl();
+        if (wrapper == null) {
+            wrapper = IContextHubWrapper.maybeConnectTo1_2();
+        }
         if (wrapper == null) {
             wrapper = IContextHubWrapper.maybeConnectTo1_1();
         }
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index df6cc05..1de749b 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -33,6 +33,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -45,6 +46,11 @@
     private static final String CONTEXT_HUB_PERMISSION = Manifest.permission.ACCESS_CONTEXT_HUB;
 
     /**
+     * A host endpoint that is reserved to identify a broadcasted message.
+     */
+    private static final char HOST_ENDPOINT_BROADCAST = 0xFFFF;
+
+    /**
      * Creates a ConcurrentHashMap of the Context Hub ID to the ContextHubInfo object given an
      * ArrayList of HIDL ContextHub objects.
      *
@@ -110,11 +116,11 @@
     }
 
     /**
-     * Generates the Context Hub HAL's NanoAppBinary object from the client-facing
+     * Generates the Context Hub HAL's HIDL NanoAppBinary object from the client-facing
      * android.hardware.location.NanoAppBinary object.
      *
      * @param nanoAppBinary the client-facing NanoAppBinary object
-     * @return the Context Hub HAL's NanoAppBinary object
+     * @return the Context Hub HAL's HIDL NanoAppBinary object
      */
     /* package */
     static android.hardware.contexthub.V1_0.NanoAppBinary createHidlNanoAppBinary(
@@ -142,6 +148,29 @@
     }
 
     /**
+     * Generates the Context Hub HAL's AIDL NanoAppBinary object from the client-facing
+     * android.hardware.location.NanoAppBinary object.
+     *
+     * @param nanoAppBinary the client-facing NanoAppBinary object
+     * @return the Context Hub HAL's AIDL NanoAppBinary object
+     */
+    /* package */
+    static android.hardware.contexthub.NanoappBinary createAidlNanoAppBinary(
+            NanoAppBinary nanoAppBinary) {
+        android.hardware.contexthub.NanoappBinary aidlNanoAppBinary =
+                new android.hardware.contexthub.NanoappBinary();
+
+        aidlNanoAppBinary.nanoappId = nanoAppBinary.getNanoAppId();
+        aidlNanoAppBinary.nanoappVersion = nanoAppBinary.getNanoAppVersion();
+        aidlNanoAppBinary.flags = nanoAppBinary.getFlags();
+        aidlNanoAppBinary.targetChreApiMajorVersion = nanoAppBinary.getTargetChreApiMajorVersion();
+        aidlNanoAppBinary.targetChreApiMinorVersion = nanoAppBinary.getTargetChreApiMinorVersion();
+        aidlNanoAppBinary.customBinary = nanoAppBinary.getBinaryNoHeader();
+
+        return aidlNanoAppBinary;
+    }
+
+    /**
      * Generates a client-facing NanoAppState array from a HAL HubAppInfo array.
      *
      * @param nanoAppInfoList the array of HubAppInfo objects
@@ -154,7 +183,26 @@
         for (HubAppInfo appInfo : nanoAppInfoList) {
             nanoAppStateList.add(
                     new NanoAppState(appInfo.info_1_0.appId, appInfo.info_1_0.version,
-                                     appInfo.info_1_0.enabled, appInfo.permissions));
+                            appInfo.info_1_0.enabled, appInfo.permissions));
+        }
+
+        return nanoAppStateList;
+    }
+
+    /**
+     * Generates a client-facing NanoAppState array from a AIDL NanoappInfo array.
+     *
+     * @param nanoAppInfoList the array of NanoappInfo objects
+     * @return the corresponding array of NanoAppState objects
+     */
+    /* package */
+    static List<NanoAppState> createNanoAppStateList(
+            android.hardware.contexthub.NanoappInfo[] nanoAppInfoList) {
+        ArrayList<NanoAppState> nanoAppStateList = new ArrayList<>();
+        for (android.hardware.contexthub.NanoappInfo appInfo : nanoAppInfoList) {
+            nanoAppStateList.add(
+                    new NanoAppState(appInfo.nanoappId, appInfo.nanoappVersion,
+                            appInfo.enabled, new ArrayList<>(Arrays.asList(appInfo.permissions))));
         }
 
         return nanoAppStateList;
@@ -180,6 +228,29 @@
     }
 
     /**
+     * Creates an AIDL ContextHubMessage object to send to a nanoapp.
+     *
+     * @param hostEndPoint the ID of the client sending the message
+     * @param message      the client-facing NanoAppMessage object describing the message
+     * @return the AIDL ContextHubMessage object
+     */
+    /* package */
+    static android.hardware.contexthub.ContextHubMessage createAidlContextHubMessage(
+            short hostEndPoint, NanoAppMessage message) {
+        android.hardware.contexthub.ContextHubMessage aidlMessage =
+                new android.hardware.contexthub.ContextHubMessage();
+
+        aidlMessage.nanoappId = message.getNanoAppId();
+        aidlMessage.hostEndPoint = (char) hostEndPoint;
+        aidlMessage.messageType = message.getMessageType();
+        aidlMessage.messageBody = message.getMessageBody();
+        // This explicit definition is required to avoid erroneous behavior at the binder.
+        aidlMessage.permissions = new String[0];
+
+        return aidlMessage;
+    }
+
+    /**
      * Creates a client-facing NanoAppMessage object to send to a client.
      *
      * @param message the HIDL ContextHubMsg object from a nanoapp
@@ -195,6 +266,20 @@
     }
 
     /**
+     * Creates a client-facing NanoAppMessage object to send to a client.
+     *
+     * @param message the AIDL ContextHubMessage object from a nanoapp
+     * @return the NanoAppMessage object
+     */
+    /* package */
+    static NanoAppMessage createNanoAppMessage(
+            android.hardware.contexthub.ContextHubMessage message) {
+        return NanoAppMessage.createMessageFromNanoApp(
+                message.nanoappId, message.messageType, message.messageBody,
+                message.hostEndPoint == HOST_ENDPOINT_BROADCAST);
+    }
+
+    /**
      * Checks for location hardware permissions.
      *
      * @param context the context of the service
@@ -274,4 +359,21 @@
                 return ContextHubService.CONTEXT_HUB_EVENT_UNKNOWN;
         }
     }
+
+    /**
+     * Converts an AIDL AsyncEventType to the corresponding ContextHubService.CONTEXT_HUB_EVENT_*.
+     *
+     * @param aidlEventType The AsyncEventType value.
+     * @return The converted event type.
+     */
+    /* package */
+    static int toContextHubEventFromAidl(int aidlEventType) {
+        switch (aidlEventType) {
+            case android.hardware.contexthub.AsyncEventType.RESTARTED:
+                return ContextHubService.CONTEXT_HUB_EVENT_RESTARTED;
+            default:
+                Log.e(TAG, "toContextHubEventFromAidl: Unknown event type: " + aidlEventType);
+                return ContextHubService.CONTEXT_HUB_EVENT_UNKNOWN;
+        }
+    }
 }
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 d733db0..6c70d9d 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -30,13 +30,17 @@
 import android.hardware.location.NanoAppMessage;
 import android.hardware.location.NanoAppState;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 import android.util.Pair;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.Set;
 
 /**
  * @hide
@@ -141,6 +145,29 @@
     }
 
     /**
+     * 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 = null;
+        final String aidlServiceName =
+                android.hardware.contexthub.IContextHub.class.getCanonicalName() + "/default";
+        if (ServiceManager.isDeclared(aidlServiceName)) {
+            proxy = android.hardware.contexthub.IContextHub.Stub.asInterface(
+                    ServiceManager.waitForService(aidlServiceName));
+            if (proxy == null) {
+                Log.e(TAG, "Context Hub AIDL service was declared but was not found");
+            }
+        } else {
+            Log.d(TAG, "Context Hub AIDL service is not declared");
+        }
+
+        return (proxy == null) ? null : new ContextHubWrapperAidl(proxy);
+    }
+
+    /**
      * Calls the appropriate getHubs function depending on the HAL version.
      */
     public abstract Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException;
@@ -258,6 +285,137 @@
     public abstract void registerCallback(int contextHubId, @NonNull ICallback callback)
             throws RemoteException;
 
+    private static class ContextHubWrapperAidl extends IContextHubWrapper {
+        private android.hardware.contexthub.IContextHub mHub;
+
+        private ICallback mCallback = null;
+
+        private ContextHubAidlCallback mAidlCallback = new ContextHubAidlCallback();
+
+        private class ContextHubAidlCallback extends
+                android.hardware.contexthub.IContextHubCallback.Stub {
+            public void handleNanoappInfo(android.hardware.contexthub.NanoappInfo[] appInfo) {
+                List<NanoAppState> nanoAppStateList =
+                        ContextHubServiceUtil.createNanoAppStateList(appInfo);
+                mCallback.handleNanoappInfo(nanoAppStateList);
+            }
+
+            public void handleContextHubMessage(android.hardware.contexthub.ContextHubMessage msg,
+                    String[] msgContentPerms) {
+                mCallback.handleNanoappMessage(
+                        (short) msg.hostEndPoint,
+                        ContextHubServiceUtil.createNanoAppMessage(msg),
+                        new ArrayList<>(Arrays.asList(msg.permissions)),
+                        new ArrayList<>(Arrays.asList(msgContentPerms)));
+            }
+
+            public void handleContextHubAsyncEvent(int evt) {
+                mCallback.handleContextHubEvent(
+                        ContextHubServiceUtil.toContextHubEventFromAidl(evt));
+            }
+
+            public void handleTransactionResult(int transactionId, boolean success) {
+                mCallback.handleTransactionResult(transactionId, success);
+            }
+        }
+
+        ContextHubWrapperAidl(android.hardware.contexthub.IContextHub hub) {
+            mHub = hub;
+        }
+
+        public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
+            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) {
+                    supportedPermissions.add(permission);
+                }
+            }
+            return new Pair(hubInfoList, new ArrayList<String>(supportedPermissions));
+        }
+
+        // TODO(b/194285834): Implement settings logic
+        public boolean supportsLocationSettingNotifications() {
+            return false;
+        }
+
+        public boolean supportsWifiSettingNotifications() {
+            return false;
+        }
+
+        public boolean supportsAirplaneModeSettingNotifications() {
+            return false;
+        }
+
+        public boolean supportsMicrophoneDisableSettingNotifications() {
+            return false;
+        }
+
+        public void onLocationSettingChanged(boolean enabled) {
+        }
+
+        public void onWifiSettingChanged(boolean enabled) {
+        }
+
+        public void onAirplaneModeSettingChanged(boolean enabled) {
+        }
+
+        public void onMicrophoneDisableSettingChanged(boolean enabled) {
+        }
+
+        @ContextHubTransaction.Result
+        public int sendMessageToContextHub(
+                short hostEndpointId, int contextHubId, NanoAppMessage message)
+                throws RemoteException {
+            return toTransactionResult(mHub.sendMessageToHub(contextHubId,
+                    ContextHubServiceUtil.createAidlContextHubMessage(hostEndpointId, message)));
+        }
+
+        @ContextHubTransaction.Result
+        public int loadNanoapp(int contextHubId, NanoAppBinary binary,
+                int transactionId) throws RemoteException {
+            android.hardware.contexthub.NanoappBinary aidlNanoAppBinary =
+                    ContextHubServiceUtil.createAidlNanoAppBinary(binary);
+            return toTransactionResult(
+                    mHub.loadNanoapp(contextHubId, aidlNanoAppBinary, transactionId));
+        }
+
+        @ContextHubTransaction.Result
+        public int unloadNanoapp(int contextHubId, long nanoappId, int transactionId)
+                throws RemoteException {
+            return toTransactionResult(mHub.unloadNanoapp(contextHubId, nanoappId, transactionId));
+        }
+
+        @ContextHubTransaction.Result
+        public int enableNanoapp(int contextHubId, long nanoappId, int transactionId)
+                throws RemoteException {
+            return toTransactionResult(mHub.enableNanoapp(contextHubId, nanoappId, transactionId));
+        }
+
+        @ContextHubTransaction.Result
+        public int disableNanoapp(int contextHubId, long nanoappId, int transactionId)
+                throws RemoteException {
+            return toTransactionResult(mHub.disableNanoapp(contextHubId, nanoappId, transactionId));
+        }
+
+        @ContextHubTransaction.Result
+        public int queryNanoapps(int contextHubId) throws RemoteException {
+            return toTransactionResult(mHub.queryNanoapps(contextHubId));
+        }
+
+        public void registerCallback(int contextHubId, ICallback callback) throws RemoteException {
+            mCallback = callback;
+            mHub.registerCallback(contextHubId, mAidlCallback);
+        }
+
+        @ContextHubTransaction.Result
+        private int toTransactionResult(boolean success) {
+            return success ? ContextHubTransaction.RESULT_SUCCESS
+                    : ContextHubTransaction.RESULT_FAILED_UNKNOWN;
+        }
+    }
+
     /**
      * An abstract call that defines methods common to all HIDL IContextHubWrappers.
      */