OSDN Git Service

Replace JNI code with Java HIDL at ContextHubService
authorArthur Ishiguro <arthuri@google.com>
Wed, 1 Nov 2017 17:52:28 +0000 (10:52 -0700)
committerArthur Ishiguro <arthuri@google.com>
Mon, 20 Nov 2017 16:59:58 +0000 (08:59 -0800)
This CL does the following:
- Use Java HIDL to communicate with the Context Hub
- Reimplement required JNI functionality in Java

Bug: 67734082
Test: Flash device and run CHQTS, verify pass on walleye-userdebug
Change-Id: I8b7563d04e9e3a22295b81af283fd3168e179957

services/core/Android.mk
services/core/java/com/android/server/location/ContextHubService.java
services/core/java/com/android/server/location/ContextHubServiceTransaction.java [new file with mode: 0644]
services/core/java/com/android/server/location/ContextHubServiceUtil.java [new file with mode: 0644]
services/core/java/com/android/server/location/ContextHubTransactionManager.java [new file with mode: 0644]
services/core/jni/Android.mk
services/core/jni/com_android_server_location_ContextHubService.cpp [deleted file]
services/core/jni/onload.cpp

index 633bb3e..3d81baf 100644 (file)
@@ -43,7 +43,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
     android.hardware.oemlock-V1.0-java \
     android.hardware.tetheroffload.control-V1.0-java \
     android.hardware.vibrator-V1.0-java \
-    android.hardware.configstore-V1.0-java
+    android.hardware.configstore-V1.0-java \
+    android.hardware.contexthub-V1.0-java
 
 ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
index 5e9f355..da481a8 100644 (file)
@@ -18,15 +18,25 @@ package com.android.server.location;
 
 import android.Manifest;
 import android.content.Context;
-import android.content.pm.PackageManager;
+import android.hardware.contexthub.V1_0.AsyncEventType;
+import android.hardware.contexthub.V1_0.ContextHub;
+import android.hardware.contexthub.V1_0.ContextHubMsg;
+import android.hardware.contexthub.V1_0.HostEndPoint;
+import android.hardware.contexthub.V1_0.HubAppInfo;
+import android.hardware.contexthub.V1_0.IContexthub;
+import android.hardware.contexthub.V1_0.IContexthubCallback;
+import android.hardware.contexthub.V1_0.Result;
+import android.hardware.contexthub.V1_0.TransactionResult;
 import android.hardware.location.ContextHubInfo;
-import android.hardware.location.ContextHubManager;
 import android.hardware.location.ContextHubMessage;
-import android.hardware.location.IContextHubService;
 import android.hardware.location.IContextHubCallback;
-import android.hardware.location.NanoAppFilter;
+import android.hardware.location.IContextHubService;
+import android.hardware.location.IContextHubTransactionCallback;
 import android.hardware.location.NanoApp;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppFilter;
 import android.hardware.location.NanoAppInstanceInfo;
+import android.hardware.location.NanoAppState;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.util.Log;
@@ -38,8 +48,10 @@ import java.io.PrintWriter;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.HashMap;
 
 /**
  * @hide
@@ -48,55 +60,152 @@ public class ContextHubService extends IContextHubService.Stub {
     private static final String TAG = "ContextHubService";
     private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
     private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
-        + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
-
-    public static final int ANY_HUB             = -1;
-    public static final int MSG_LOAD_NANO_APP   = 3;
+            + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
+
+    /*
+     * Constants for the type of transaction that is defined by ContextHubService.
+     * This is used to report the transaction callback to clients, and is different from
+     * ContextHubTransaction.Type.
+     */
+    public static final int MSG_ENABLE_NANO_APP = 1;
+    public static final int MSG_DISABLE_NANO_APP = 2;
+    public static final int MSG_LOAD_NANO_APP = 3;
     public static final int MSG_UNLOAD_NANO_APP = 4;
+    public static final int MSG_QUERY_NANO_APPS = 5;
+    public static final int MSG_QUERY_MEMORY = 6;
+    public static final int MSG_HUB_RESET = 7;
 
     private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
     private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
     private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
     private static final int PRE_LOADED_APP_MEM_REQ = 0;
 
-    private static final int MSG_HEADER_SIZE = 4;
-    private static final int HEADER_FIELD_MSG_TYPE = 0;
-    private static final int HEADER_FIELD_MSG_VERSION = 1;
-    private static final int HEADER_FIELD_HUB_HANDLE = 2;
-    private static final int HEADER_FIELD_APP_INSTANCE = 3;
-
-    private static final int HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
-    private static final int HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
-    private static final int MSG_LOAD_APP_HEADER_SIZE = MSG_HEADER_SIZE + 2;
-
     private static final int OS_APP_INSTANCE = -1;
 
     private final Context mContext;
+
+    // TODO(b/69270990): Remove once old ContextHubManager API is deprecated
+    // Service cache maintaining of instance ID to nanoapp infos
     private final ConcurrentHashMap<Integer, NanoAppInstanceInfo> mNanoAppHash =
             new ConcurrentHashMap<>();
+    // The next available instance ID (managed by the service) to assign to a nanoapp
+    private int mNextAvailableInstanceId = 0;
+    // A map of the long nanoapp ID to instance ID managed by the service
+    private final ConcurrentHashMap<Long, Integer> mNanoAppIdToInstanceMap =
+            new ConcurrentHashMap<>();
+
     private final ContextHubInfo[] mContextHubInfo;
     private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
             new RemoteCallbackList<>();
 
-    private native int nativeSendMessage(int[] header, byte[] data);
-    private native ContextHubInfo[] nativeInitialize();
+    // Proxy object to communicate with the Context Hub HAL
+    private final IContexthub mContextHubProxy;
+
+    // The manager for transaction queue
+    private final ContextHubTransactionManager mTransactionManager;
+
+    /**
+     * Class extending the callback to register with a Context Hub.
+     */
+    private class ContextHubServiceCallback extends IContexthubCallback.Stub {
+        private final int mContextHubId;
+
+        ContextHubServiceCallback(int contextHubId) {
+            mContextHubId = contextHubId;
+        }
+
+        @Override
+        public void handleClientMsg(ContextHubMsg message) {
+            handleClientMessageCallback(mContextHubId, message);
+        }
+
+        @Override
+        public void handleTxnResult(int transactionId, int result) {
+            handleTransactionResultCallback(mContextHubId, transactionId, result);
+        }
+
+        @Override
+        public void handleHubEvent(int eventType) {
+            handleHubEventCallback(mContextHubId, eventType);
+        }
+
+        @Override
+        public void handleAppAbort(long nanoAppId, int abortCode) {
+            handleAppAbortCallback(mContextHubId, nanoAppId, abortCode);
+        }
+
+        @Override
+        public void handleAppsInfo(ArrayList<HubAppInfo> nanoAppInfoList) {
+            handleQueryAppsCallback(mContextHubId, nanoAppInfoList);
+        }
+    }
 
     public ContextHubService(Context context) {
         mContext = context;
-        mContextHubInfo = nativeInitialize();
+
+        mContextHubProxy = getContextHubProxy();
+        if (mContextHubProxy == null) {
+            mTransactionManager = null;
+            mContextHubInfo = new ContextHubInfo[0];
+            return;
+        }
+
+        mTransactionManager = new ContextHubTransactionManager(mContextHubProxy);
+
+        List<ContextHub> hubList;
+        try {
+            hubList = mContextHubProxy.getHubs();
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException while getting Context Hub info");
+            hubList = Collections.emptyList();
+        }
+        mContextHubInfo = ContextHubServiceUtil.createContextHubInfoArray(hubList);
+
+        for (ContextHubInfo contextHubInfo : mContextHubInfo) {
+            int contextHubId = contextHubInfo.getId();
+            try {
+                mContextHubProxy.registerCallback(
+                        contextHubId, new ContextHubServiceCallback(contextHubId));
+            } catch (RemoteException e) {
+                Log.e(TAG, "RemoteException while registering service callback for hub (ID = "
+                        + contextHubId + ")");
+            }
+        }
+
+        // Do a query to initialize the service cache list of nanoapps
+        // TODO(b/69270990): Remove this when old API is deprecated
+        for (ContextHubInfo contextHubInfo : mContextHubInfo) {
+            queryNanoAppsInternal(contextHubInfo.getId());
+        }
 
         for (int i = 0; i < mContextHubInfo.length; i++) {
             Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
-                  + ", name:  " + mContextHubInfo[i].getName());
+                    + ", name:  " + mContextHubInfo[i].getName());
         }
     }
 
+    /**
+     * @return the IContexthub proxy interface
+     */
+    private IContexthub getContextHubProxy() {
+        IContexthub proxy = null;
+        try {
+            proxy = IContexthub.getService(true /* retry */);
+        } catch (RemoteException e) {
+            Log.e(TAG, "RemoteException while attaching to Context Hub HAL proxy");
+        } catch (NoSuchElementException e) {
+            Log.i(TAG, "Context Hub HAL service not found");
+        }
+
+        return proxy;
+    }
+
     @Override
     public int registerCallback(IContextHubCallback callback) throws RemoteException {
         checkPermissions();
         mCallbacksList.register(callback);
         Log.d(TAG, "Added callback, total callbacks " +
-              mCallbacksList.getRegisteredCallbackCount());
+                mCallbacksList.getRegisteredCallbackCount());
         return 0;
     }
 
@@ -109,29 +218,112 @@ public class ContextHubService extends IContextHubService.Stub {
         for (int i = 0; i < returnArray.length; ++i) {
             returnArray[i] = i;
             Log.d(TAG, String.format("Hub %s is mapped to %d",
-                                     mContextHubInfo[i].getName(), returnArray[i]));
+                    mContextHubInfo[i].getName(), returnArray[i]));
         }
 
         return returnArray;
     }
 
     @Override
-    public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
+    public ContextHubInfo getContextHubInfo(int contextHubId) throws RemoteException {
         checkPermissions();
-        if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
-            Log.e(TAG, "Invalid context hub handle " + contextHubHandle);
+        if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
+            Log.e(TAG, "Invalid context hub handle " + contextHubId);
             return null; // null means fail
         }
 
-        return mContextHubInfo[contextHubHandle];
+        return mContextHubInfo[contextHubId];
+    }
+
+    /**
+     * Creates an internal load transaction callback to be used for old API clients
+     *
+     * @param contextHubId  the ID of the hub to load the binary
+     * @param nanoAppBinary the binary to load
+     * @return the callback interface
+     */
+    private IContextHubTransactionCallback createLoadTransactionCallback(
+            int contextHubId, NanoAppBinary nanoAppBinary) {
+        return new IContextHubTransactionCallback.Stub() {
+            @Override
+            public void onTransactionComplete(int result) {
+                handleLoadResponseOldApi(contextHubId, result, nanoAppBinary);
+            }
+
+            @Override
+            public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
+            }
+        };
+    }
+
+    /**
+     * Creates an internal unload transaction callback to be used for old API clients
+     *
+     * @param contextHubId the ID of the hub to unload the nanoapp
+     * @param nanoAppId    the ID of the nanoapp to unload
+     * @return the callback interface
+     */
+    private IContextHubTransactionCallback createUnloadTransactionCallback(
+            int contextHubId, long nanoAppId) {
+        return new IContextHubTransactionCallback.Stub() {
+            @Override
+            public void onTransactionComplete(int result) {
+                handleUnloadResponseOldApi(contextHubId, result, nanoAppId);
+            }
+
+            @Override
+            public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
+            }
+        };
+    }
+
+    /**
+     * Creates an internal query transaction callback to be used for old API clients
+     *
+     * @param contextHubId the ID of the hub to query
+     * @return the callback interface
+     */
+    private IContextHubTransactionCallback createQueryTransactionCallback(int contextHubId) {
+        return new IContextHubTransactionCallback.Stub() {
+            @Override
+            public void onTransactionComplete(int result) {
+            }
+
+            @Override
+            public void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
+                byte[] data = {(byte) result};
+                onMessageReceipt(MSG_QUERY_NANO_APPS, contextHubId, OS_APP_INSTANCE, data);
+            }
+        };
+    }
+
+    /**
+     * Adds a new transaction to the transaction manager queue
+     *
+     * @param transaction the transaction to add
+     * @return the result of adding the transaction
+     */
+    private int addTransaction(ContextHubServiceTransaction transaction) {
+        int result = Result.OK;
+        try {
+            mTransactionManager.addTransaction(transaction);
+        } catch (IllegalStateException e) {
+            Log.e(TAG, e.getMessage());
+            result = Result.TRANSACTION_PENDING; /* failed */
+        }
+
+        return result;
     }
 
     @Override
-    public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
+    public int loadNanoApp(int contextHubId, NanoApp app) throws RemoteException {
         checkPermissions();
+        if (mContextHubProxy == null) {
+            return -1;
+        }
 
-        if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
-            Log.e(TAG, "Invalid contextHubhandle " + contextHubHandle);
+        if (!(contextHubId >= 0 && contextHubId < mContextHubInfo.length)) {
+            Log.e(TAG, "Invalid contextHubhandle " + contextHubId);
             return -1;
         }
         if (app == null) {
@@ -139,20 +331,17 @@ public class ContextHubService extends IContextHubService.Stub {
             return -1;
         }
 
-        int[] msgHeader = new int[MSG_LOAD_APP_HEADER_SIZE];
-        msgHeader[HEADER_FIELD_HUB_HANDLE] = contextHubHandle;
-        msgHeader[HEADER_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
-        msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
-        msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_LOAD_NANO_APP;
-
-        long appId = app.getAppId();
+        // Create an internal IContextHubTransactionCallback for the old API clients
+        NanoAppBinary nanoAppBinary = new NanoAppBinary(app.getAppBinary());
+        IContextHubTransactionCallback onCompleteCallback =
+                createLoadTransactionCallback(contextHubId, nanoAppBinary);
 
-        msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
-        msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
+        ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
+                contextHubId, nanoAppBinary, onCompleteCallback);
 
-        int errVal = nativeSendMessage(msgHeader, app.getAppBinary());
-        if (errVal != 0) {
-            Log.e(TAG, "Send Message returns error" + contextHubHandle);
+        int result = addTransaction(transaction);
+        if (result != Result.OK) {
+            Log.e(TAG, "Failed to load nanoapp with error code " + result);
             return -1;
         }
 
@@ -163,23 +352,26 @@ public class ContextHubService extends IContextHubService.Stub {
     @Override
     public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
         checkPermissions();
+        if (mContextHubProxy == null) {
+            return -1;
+        }
+
         NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
         if (info == null) {
             Log.e(TAG, "Cannot find app with handle " + nanoAppInstanceHandle);
             return -1; //means failed
         }
 
-        // Call Native interface here
-        int[] msgHeader = new int[MSG_HEADER_SIZE];
-        msgHeader[HEADER_FIELD_HUB_HANDLE] = ANY_HUB;
-        msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppInstanceHandle;
-        msgHeader[HEADER_FIELD_MSG_VERSION] = 0;
-        msgHeader[HEADER_FIELD_MSG_TYPE] = MSG_UNLOAD_NANO_APP;
-
-        byte msg[] = new byte[0];
+        int contextHubId = info.getContexthubId();
+        long nanoAppId = info.getAppId();
+        IContextHubTransactionCallback onCompleteCallback =
+                createUnloadTransactionCallback(contextHubId, nanoAppId);
+        ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
+                contextHubId, nanoAppId, onCompleteCallback);
 
-        if (nativeSendMessage(msgHeader, msg) != 0) {
-            Log.e(TAG, "native send message fails");
+        int result = addTransaction(transaction);
+        if (result != Result.OK) {
+            Log.e(TAG, "Failed to unload nanoapp with error code " + result);
             return -1;
         }
 
@@ -189,7 +381,7 @@ public class ContextHubService extends IContextHubService.Stub {
 
     @Override
     public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
-                                                      throws RemoteException {
+            throws RemoteException {
         checkPermissions();
         // This assumes that all the nanoAppInfo is current. This is reasonable
         // for the use cases for tightly controlled nanoApps.
@@ -206,7 +398,7 @@ public class ContextHubService extends IContextHubService.Stub {
         checkPermissions();
         ArrayList<Integer> foundInstances = new ArrayList<Integer>();
 
-        for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
+        for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
             NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
 
             if (filter.testMatch(info)) {
@@ -223,23 +415,230 @@ public class ContextHubService extends IContextHubService.Stub {
         return retArray;
     }
 
+    /**
+     * Performs a query at the specified hub.
+     *
+     * This method should only be invoked internally by the service, either to update the service
+     * cache or as a result of an explicit query requested by a client through the sendMessage API.
+     *
+     * @param contextHubId the ID of the hub to do the query
+     * @return the result of the query
+     */
+    private int queryNanoAppsInternal(int contextHubId) {
+        if (mContextHubProxy == null) {
+            return Result.UNKNOWN_FAILURE;
+        }
+
+        IContextHubTransactionCallback onCompleteCallback =
+                createQueryTransactionCallback(contextHubId);
+        ContextHubServiceTransaction transaction = mTransactionManager.createQueryTransaction(
+                contextHubId, onCompleteCallback);
+
+        return addTransaction(transaction);
+    }
+
     @Override
-    public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
-                           throws RemoteException {
+    public int sendMessage(
+            int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
         checkPermissions();
-
-        if (msg == null || msg.getData() == null) {
-            Log.w(TAG, "null ptr");
+        if (mContextHubProxy == null) {
+            return -1;
+        }
+        if (msg == null) {
+            Log.e(TAG, "ContextHubMessage cannot be null");
             return -1;
         }
+        if (msg.getData() == null) {
+            Log.w(TAG, "ContextHubMessage message body cannot be null");
+            return -1;
+        }
+
+        int result;
+        if (nanoAppHandle == OS_APP_INSTANCE) {
+            if (msg.getMsgType() == MSG_QUERY_NANO_APPS) {
+                result = queryNanoAppsInternal(hubHandle);
+            } else {
+                Log.e(TAG, "Invalid OS message params of type " + msg.getMsgType());
+                result = Result.BAD_PARAMS;
+            }
+        } else {
+            NanoAppInstanceInfo info = getNanoAppInstanceInfo(nanoAppHandle);
+            if (info != null) {
+                ContextHubMsg hubMessage = new ContextHubMsg();
+                hubMessage.appName = info.getAppId();
+                hubMessage.msgType = msg.getMsgType();
+                hubMessage.hostEndPoint = HostEndPoint.UNSPECIFIED;
+                ContextHubServiceUtil.copyToByteArrayList(msg.getData(), hubMessage.msg);
+
+                try {
+                    result = mContextHubProxy.sendMessageToHub(hubHandle, hubMessage);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "Failed to send nanoapp message - RemoteException");
+                    result = Result.UNKNOWN_FAILURE;
+                }
+            } else {
+                Log.e(TAG, "Failed to send nanoapp message - nanoapp with instance ID "
+                        + nanoAppHandle + " does not exist.");
+                result = Result.BAD_PARAMS;
+            }
+        }
 
-        int[] msgHeader = new int[MSG_HEADER_SIZE];
-        msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
-        msgHeader[HEADER_FIELD_APP_INSTANCE] = nanoAppHandle;
-        msgHeader[HEADER_FIELD_MSG_VERSION] = msg.getVersion();
-        msgHeader[HEADER_FIELD_MSG_TYPE] = msg.getMsgType();
+        return (result == Result.OK ? 0 : -1);
+    }
 
-        return nativeSendMessage(msgHeader, msg.getData());
+    /**
+     * Handles a unicast or broadcast message from a nanoapp.
+     *
+     * @param contextHubId the ID of the hub the message came from
+     * @param message      the message contents
+     */
+    private void handleClientMessageCallback(int contextHubId, ContextHubMsg message) {
+        // TODO(b/67734082): Send to new API clients
+        byte[] data = ContextHubServiceUtil.createPrimitiveByteArray(message.msg);
+
+        int nanoAppInstanceId = mNanoAppIdToInstanceMap.containsKey(message.appName) ?
+                mNanoAppIdToInstanceMap.get(message.appName) : -1;
+        onMessageReceipt(message.msgType, contextHubId, nanoAppInstanceId, data);
+    }
+
+    /**
+     * A helper function to handle a load response from the Context Hub for the old API.
+     *
+     * TODO(b/69270990): Remove this once the old APIs are obsolete.
+     */
+    private void handleLoadResponseOldApi(
+            int contextHubId, int result, NanoAppBinary nanoAppBinary) {
+        if (nanoAppBinary == null) {
+            Log.e(TAG, "Nanoapp binary field was null for a load transaction");
+            return;
+        }
+
+        // NOTE: The legacy JNI code used to do a query right after a load success
+        // to synchronize the service cache. Instead store the binary that was requested to
+        // load to update the cache later without doing a query.
+        int instanceId = 0;
+        long nanoAppId = nanoAppBinary.getNanoAppId();
+        int nanoAppVersion = nanoAppBinary.getNanoAppVersion();
+        if (result == TransactionResult.SUCCESS) {
+            if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
+                instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
+            } else {
+                instanceId = mNextAvailableInstanceId++;
+                mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
+            }
+
+            addAppInstance(contextHubId, instanceId, nanoAppId, nanoAppVersion);
+        }
+
+        byte[] data = new byte[5];
+        data[0] = (byte) result;
+        ByteBuffer.wrap(data, 1, 4).order(ByteOrder.nativeOrder()).putInt(instanceId);
+
+        onMessageReceipt(MSG_LOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
+    }
+
+    /**
+     * A helper function to handle an unload response from the Context Hub for the old API.
+     *
+     * TODO(b/69270990): Remove this once the old APIs are obsolete.
+     */
+    private void handleUnloadResponseOldApi(
+            int contextHubId, int result, long nanoAppId) {
+        if (result == TransactionResult.SUCCESS) {
+            int instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
+            deleteAppInstance(instanceId);
+            mNanoAppIdToInstanceMap.remove(nanoAppId);
+        }
+
+        byte[] data = new byte[1];
+        data[0] = (byte) result;
+        onMessageReceipt(MSG_UNLOAD_NANO_APP, contextHubId, OS_APP_INSTANCE, data);
+    }
+
+    /**
+     * Handles a transaction response from a Context Hub.
+     *
+     * @param contextHubId  the ID of the hub the response came from
+     * @param transactionId the ID of the transaction
+     * @param result        the result of the transaction reported by the hub
+     */
+    private void handleTransactionResultCallback(int contextHubId, int transactionId, int result) {
+        mTransactionManager.onTransactionResponse(transactionId, result);
+    }
+
+    /**
+     * Handles an asynchronous event from a Context Hub.
+     *
+     * @param contextHubId the ID of the hub the response came from
+     * @param eventType    the type of the event as defined in Context Hub HAL AsyncEventType
+     */
+    private void handleHubEventCallback(int contextHubId, int eventType) {
+        if (eventType == AsyncEventType.RESTARTED) {
+            mTransactionManager.onHubReset();
+            queryNanoAppsInternal(contextHubId);
+
+            byte[] data = {TransactionResult.SUCCESS};
+            onMessageReceipt(MSG_HUB_RESET, contextHubId, OS_APP_INSTANCE, data);
+        } else {
+            Log.i(TAG, "Received unknown hub event (hub ID = " + contextHubId + ", type = "
+                    + eventType + ")");
+        }
+    }
+
+    /**
+     * Handles an asynchronous abort event of a nanoapp.
+     *
+     * @param contextHubId the ID of the hub that the nanoapp aborted in
+     * @param nanoAppId    the ID of the aborted nanoapp
+     * @param abortCode    the nanoapp-specific abort code
+     */
+    private void handleAppAbortCallback(int contextHubId, long nanoAppId, int abortCode) {
+        // TODO(b/31049861): Implement this
+    }
+
+    /**
+     * Handles a query response from a Context Hub.
+     *
+     * @param contextHubId    the ID of the hub of the response
+     * @param nanoAppInfoList the list of loaded nanoapps
+     */
+    private void handleQueryAppsCallback(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
+        List<NanoAppState> nanoAppStateList =
+                ContextHubServiceUtil.createNanoAppStateList(nanoAppInfoList);
+
+        updateServiceCache(contextHubId, nanoAppInfoList);
+        mTransactionManager.onQueryResponse(nanoAppStateList);
+    }
+
+    /**
+     * Updates the service's cache of the list of loaded nanoapps using a nanoapp list response.
+     *
+     * TODO(b/69270990): Remove this when the old API functionality is removed.
+     *
+     * @param contextHubId    the ID of the hub the response came from
+     * @param nanoAppInfoList the list of loaded nanoapps
+     */
+    private void updateServiceCache(int contextHubId, List<HubAppInfo> nanoAppInfoList) {
+        synchronized (mNanoAppHash) {
+            for (int instanceId : mNanoAppHash.keySet()) {
+                if (mNanoAppHash.get(instanceId).getContexthubId() == contextHubId) {
+                    deleteAppInstance(instanceId);
+                }
+            }
+
+            for (HubAppInfo appInfo : nanoAppInfoList) {
+                int instanceId;
+                long nanoAppId = appInfo.appId;
+                if (mNanoAppIdToInstanceMap.containsKey(nanoAppId)) {
+                    instanceId = mNanoAppIdToInstanceMap.get(nanoAppId);
+                } else {
+                    instanceId = mNextAvailableInstanceId++;
+                    mNanoAppIdToInstanceMap.put(nanoAppId, instanceId);
+                }
+
+                addAppInstance(contextHubId, instanceId, nanoAppId, appInfo.version);
+            }
+        }
     }
 
     @Override
@@ -257,7 +656,7 @@ public class ContextHubService extends IContextHubService.Stub {
         pw.println("");
         pw.println("=================== NANOAPPS ====================");
         // Dump nanoAppHash
-        for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
+        for (Integer nanoAppInstance : mNanoAppHash.keySet()) {
             pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
         }
 
@@ -268,19 +667,15 @@ public class ContextHubService extends IContextHubService.Stub {
         mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
     }
 
-    private int onMessageReceipt(int[] header, byte[] data) {
-        if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
-            return  -1;
+    private int onMessageReceipt(int msgType, int hubHandle, int appInstance, byte[] data) {
+        if (data == null) {
+            return -1;
         }
 
+        int msgVersion = 0;
         int callbacksCount = mCallbacksList.beginBroadcast();
-        int msgType = header[HEADER_FIELD_MSG_TYPE];
-        int msgVersion = header[HEADER_FIELD_MSG_VERSION];
-        int hubHandle = header[HEADER_FIELD_HUB_HANDLE];
-        int appInstance = header[HEADER_FIELD_APP_INSTANCE];
-
         Log.d(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle " +
-              hubHandle + ", appInstance " + appInstance + ", callBackCount " + callbacksCount);
+                hubHandle + ", appInstance " + appInstance + ", callBackCount " + callbacksCount);
 
         if (callbacksCount < 1) {
             Log.v(TAG, "No message callbacks registered.");
@@ -323,8 +718,8 @@ public class ContextHubService extends IContextHubService.Stub {
         }
 
         mNanoAppHash.put(appInstanceHandle, appInfo);
-        Log.d(TAG, action + " app instance " + appInstanceHandle + " with id "
-              + appId + " version " + appVersion);
+        Log.d(TAG, action + " app instance " + appInstanceHandle + " with id 0x"
+                + Long.toHexString(appId) + " version 0x" + Integer.toHexString(appVersion));
 
         return 0;
     }
diff --git a/services/core/java/com/android/server/location/ContextHubServiceTransaction.java b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
new file mode 100644 (file)
index 0000000..66145bb
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.hardware.location.ContextHubTransaction;
+import android.hardware.location.NanoAppState;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An abstract class representing transactions requested to the Context Hub Service.
+ *
+ * @hide
+ */
+/* package */ abstract class ContextHubServiceTransaction {
+    private final int mTransactionId;
+    @ContextHubTransaction.Type
+    private final int mTransactionType;
+
+    /*
+     * true if the transaction has already completed, false otherwise
+     */
+    private boolean mIsComplete = false;
+
+    /* package */ ContextHubServiceTransaction(int id, int type) {
+        mTransactionId = id;
+        mTransactionType = type;
+    }
+
+    /**
+     * Starts this transaction with a Context Hub.
+     *
+     * All instances of this class must implement this method by making an asynchronous request to
+     * a hub.
+     *
+     * @return the synchronous error code of the transaction start
+     */
+    /* package */
+    abstract int onTransact();
+
+    /**
+     * A function to invoke when a transaction times out.
+     *
+     * All instances of this class must implement this method by reporting the timeout to the
+     * client.
+     */
+    /* package */
+    abstract void onTimeout();
+
+    /**
+     * A function to invoke when the transaction completes.
+     *
+     * Only relevant for load, unload, enable, or disable transactions.
+     *
+     * @param result the result of the transaction
+     */
+    /* package */ void onTransactionComplete(int result) {
+    }
+
+    /**
+     * A function to invoke when a query transaction completes.
+     *
+     * Only relevant for query transactions.
+     *
+     * @param result           the result of the query
+     * @param nanoAppStateList the list of nanoapps given by the query response
+     */
+    /* package */ void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
+    }
+
+    /**
+     * @return the ID of this transaction
+     */
+    /* package */ int getTransactionId() {
+        return mTransactionId;
+    }
+
+    /**
+     * @return the type of this transaction
+     * @see ContextHubTransaction.Type
+     */
+    @ContextHubTransaction.Type
+    /* package */ int getTransactionType() {
+        return mTransactionType;
+    }
+
+    /**
+     * Gets the timeout period as defined in IContexthub.hal
+     *
+     * @return the timeout of this transaction in the specified time unit
+     */
+    /* package */ long getTimeout(TimeUnit unit) {
+        switch (mTransactionType) {
+            case ContextHubTransaction.TYPE_LOAD_NANOAPP:
+                return unit.convert(30L, TimeUnit.SECONDS);
+            case ContextHubTransaction.TYPE_UNLOAD_NANOAPP:
+            case ContextHubTransaction.TYPE_ENABLE_NANOAPP:
+            case ContextHubTransaction.TYPE_DISABLE_NANOAPP:
+            case ContextHubTransaction.TYPE_QUERY_NANOAPPS:
+                // Note: query timeout is not specified at the HAL
+            default: /* fall through */
+                return unit.convert(5L, TimeUnit.SECONDS);
+        }
+    }
+
+    /**
+     * Marks the transaction as complete.
+     *
+     * Should only be called as a result of a response from a Context Hub callback
+     */
+    /* package */ void setComplete() {
+        mIsComplete = true;
+    }
+
+    /**
+     * @return true if the transaction has already completed, false otherwise
+     */
+    /* package */ boolean isComplete() {
+        return mIsComplete;
+    }
+
+    /**
+     * @return the human-readable string of this transaction's type
+     */
+    private String getTransactionTypeString() {
+        switch (mTransactionType) {
+            case ContextHubTransaction.TYPE_LOAD_NANOAPP:
+                return "Load";
+            case ContextHubTransaction.TYPE_UNLOAD_NANOAPP:
+                return "Unload";
+            case ContextHubTransaction.TYPE_ENABLE_NANOAPP:
+                return "Enable";
+            case ContextHubTransaction.TYPE_DISABLE_NANOAPP:
+                return "Disable";
+            case ContextHubTransaction.TYPE_QUERY_NANOAPPS:
+                return "Query";
+            default:
+                return "Unknown";
+        }
+    }
+
+    @Override
+    public String toString() {
+        return getTransactionTypeString() + " transaction (ID = " + mTransactionId + ")";
+    }
+}
diff --git a/services/core/java/com/android/server/location/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
new file mode 100644 (file)
index 0000000..568d027
--- /dev/null
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.hardware.contexthub.V1_0.ContextHub;
+import android.hardware.contexthub.V1_0.HubAppInfo;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppState;
+import android.util.Log;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * A class encapsulating helper functions used by the ContextHubService class
+ */
+/* package */ class ContextHubServiceUtil {
+    private static final String TAG = "ContextHubServiceUtil";
+
+    /**
+     * Creates a ContextHubInfo array from an ArrayList of HIDL ContextHub objects.
+     *
+     * @param hubList the ContextHub ArrayList
+     * @return the ContextHubInfo array
+     */
+    /* package */
+    static ContextHubInfo[] createContextHubInfoArray(List<ContextHub> hubList) {
+        ContextHubInfo[] contextHubInfoList = new ContextHubInfo[hubList.size()];
+        for (int i = 0; i < hubList.size(); i++) {
+            contextHubInfoList[i] = new ContextHubInfo(hubList.get(i));
+        }
+
+        return contextHubInfoList;
+    }
+
+    /**
+     * Copies a primitive byte array to a ArrayList<Byte>.
+     *
+     * @param inputArray  the primitive byte array
+     * @param outputArray the ArrayList<Byte> array to append
+     */
+    /* package */
+    static void copyToByteArrayList(byte[] inputArray, ArrayList<Byte> outputArray) {
+        outputArray.clear();
+        outputArray.ensureCapacity(inputArray.length);
+        for (byte element : inputArray) {
+            outputArray.add(element);
+        }
+    }
+
+    /**
+     * Creates a byte array given a ArrayList<Byte> and copies its contents.
+     *
+     * @param array the ArrayList<Byte> object
+     * @return the byte array
+     */
+    /* package */
+    static byte[] createPrimitiveByteArray(ArrayList<Byte> array) {
+        byte[] primitiveArray = new byte[array.size()];
+        for (int i = 0; i < array.size(); i++) {
+            primitiveArray[i] = array.get(i);
+        }
+
+        return primitiveArray;
+    }
+
+    /**
+     * Generates the Context Hub HAL's 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
+     */
+    /* package */
+    static android.hardware.contexthub.V1_0.NanoAppBinary createHidlNanoAppBinary(
+            NanoAppBinary nanoAppBinary) {
+        android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary =
+                new android.hardware.contexthub.V1_0.NanoAppBinary();
+
+        hidlNanoAppBinary.appId = nanoAppBinary.getNanoAppId();
+        hidlNanoAppBinary.appVersion = nanoAppBinary.getNanoAppVersion();
+        hidlNanoAppBinary.flags = nanoAppBinary.getFlags();
+        hidlNanoAppBinary.targetChreApiMajorVersion = nanoAppBinary.getTargetChreApiMajorVersion();
+        hidlNanoAppBinary.targetChreApiMinorVersion = nanoAppBinary.getTargetChreApiMinorVersion();
+
+        // Log exceptions while processing the binary, but continue to pass down the binary
+        // since the error checking is deferred to the Context Hub.
+        try {
+            copyToByteArrayList(nanoAppBinary.getBinaryNoHeader(), hidlNanoAppBinary.customBinary);
+        } catch (IndexOutOfBoundsException e) {
+            Log.w(TAG, e.getMessage());
+        } catch (NullPointerException e) {
+            Log.w(TAG, "NanoApp binary was null");
+        }
+
+        return hidlNanoAppBinary;
+    }
+
+    /**
+     * Generates a client-facing NanoAppState array from a HAL HubAppInfo array.
+     *
+     * @param nanoAppInfoList the array of HubAppInfo objects
+     * @return the corresponding array of NanoAppState objects
+     */
+    /* package */
+    static List<NanoAppState> createNanoAppStateList(
+            List<HubAppInfo> nanoAppInfoList) {
+        ArrayList<NanoAppState> nanoAppStateList = new ArrayList<>();
+        for (HubAppInfo appInfo : nanoAppInfoList) {
+            nanoAppStateList.add(
+                    new NanoAppState(appInfo.appId, appInfo.version, appInfo.enabled));
+        }
+
+        return nanoAppStateList;
+    }
+}
diff --git a/services/core/java/com/android/server/location/ContextHubTransactionManager.java b/services/core/java/com/android/server/location/ContextHubTransactionManager.java
new file mode 100644 (file)
index 0000000..898b76c
--- /dev/null
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.location;
+
+import android.hardware.contexthub.V1_0.IContexthub;
+import android.hardware.contexthub.V1_0.Result;
+import android.hardware.contexthub.V1_0.TransactionResult;
+import android.hardware.location.ContextHubTransaction;
+import android.hardware.location.IContextHubTransactionCallback;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppState;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Manages transactions at the Context Hub Service.
+ *
+ * This class maintains a queue of transaction requests made to the ContextHubService by clients,
+ * and executes them through the Context Hub. At any point in time, either the transaction queue is
+ * empty, or there is a pending transaction that is waiting for an asynchronous response from the
+ * hub. This class also handles synchronous errors and timeouts of each transaction.
+ *
+ * @hide
+ */
+/* package */ class ContextHubTransactionManager {
+    private static final String TAG = "ContextHubTransactionManager";
+
+    /*
+     * Maximum number of transaction requests that can be pending at a time
+     */
+    private static final int MAX_PENDING_REQUESTS = 10;
+
+    /*
+     * The proxy to talk to the Context Hub
+     */
+    private final IContexthub mContextHubProxy;
+
+    /*
+     * A queue containing the current transactions
+     */
+    private final ArrayDeque<ContextHubServiceTransaction> mTransactionQueue = new ArrayDeque<>();
+
+    /*
+     * The next available transaction ID
+     */
+    private final AtomicInteger mNextAvailableId = new AtomicInteger();
+
+    /*
+     * An executor and the future object for scheduling timeout timers
+     */
+    private final ScheduledThreadPoolExecutor mTimeoutExecutor = new ScheduledThreadPoolExecutor(1);
+    private ScheduledFuture<?> mTimeoutFuture = null;
+
+    /* package */ ContextHubTransactionManager(IContexthub contextHubProxy) {
+        mContextHubProxy = contextHubProxy;
+    }
+
+    /**
+     * Creates a transaction for loading a nanoapp.
+     *
+     * @param contextHubId       the ID of the hub to load the nanoapp to
+     * @param nanoAppBinary      the binary of the nanoapp to load
+     * @param onCompleteCallback the client on complete callback
+     * @return the generated transaction
+     */
+    /* package */ ContextHubServiceTransaction createLoadTransaction(
+            int contextHubId, NanoAppBinary nanoAppBinary,
+            IContextHubTransactionCallback onCompleteCallback) {
+        return new ContextHubServiceTransaction(
+                mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_LOAD_NANOAPP) {
+            @Override
+            /* package */ int onTransact() {
+                android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary =
+                        ContextHubServiceUtil.createHidlNanoAppBinary(nanoAppBinary);
+                try {
+                    return mContextHubProxy.loadNanoApp(
+                            contextHubId, hidlNanoAppBinary, this.getTransactionId());
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException while trying to load nanoapp with ID 0x" +
+                            Long.toHexString(nanoAppBinary.getNanoAppId()));
+                    return Result.UNKNOWN_FAILURE;
+                }
+            }
+
+            @Override
+            /* package */ void onTimeout() {
+                onTransactionComplete(ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT);
+            }
+
+            @Override
+            /* package */ void onTransactionComplete(int result) {
+                try {
+                    onCompleteCallback.onTransactionComplete(result);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException while calling client onTransactionComplete");
+                }
+            }
+        };
+    }
+
+    /**
+     * Creates a transaction for unloading a nanoapp.
+     *
+     * @param contextHubId       the ID of the hub to load the nanoapp to
+     * @param nanoAppId          the ID of the nanoapp to unload
+     * @param onCompleteCallback the client on complete callback
+     * @return the generated transaction
+     */
+    /* package */ ContextHubServiceTransaction createUnloadTransaction(
+            int contextHubId, long nanoAppId, IContextHubTransactionCallback onCompleteCallback) {
+        return new ContextHubServiceTransaction(
+                mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_UNLOAD_NANOAPP) {
+            @Override
+            /* package */ int onTransact() {
+                try {
+                    return mContextHubProxy.unloadNanoApp(
+                            contextHubId, nanoAppId, this.getTransactionId());
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException while trying to unload nanoapp with ID 0x" +
+                            Long.toHexString(nanoAppId));
+                    return Result.UNKNOWN_FAILURE;
+                }
+            }
+
+            @Override
+            /* package */ void onTimeout() {
+                onTransactionComplete(ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT);
+            }
+
+            @Override
+            /* package */ void onTransactionComplete(int result) {
+                try {
+                    onCompleteCallback.onTransactionComplete(result);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException while calling client onTransactionComplete");
+                }
+            }
+        };
+    }
+
+    /**
+     * Creates a transaction for querying for a list of nanoapps.
+     *
+     * @param contextHubId       the ID of the hub to query
+     * @param onCompleteCallback the client on complete callback
+     * @return the generated transaction
+     */
+    /* package */ ContextHubServiceTransaction createQueryTransaction(
+            int contextHubId, IContextHubTransactionCallback onCompleteCallback) {
+        return new ContextHubServiceTransaction(
+                mNextAvailableId.getAndIncrement(), ContextHubTransaction.TYPE_QUERY_NANOAPPS) {
+            @Override
+            /* package */ int onTransact() {
+                try {
+                    return mContextHubProxy.queryApps(contextHubId);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException while trying to query for nanoapps");
+                    return Result.UNKNOWN_FAILURE;
+                }
+            }
+
+            @Override
+            /* package */ void onTimeout() {
+                onQueryResponse(ContextHubTransaction.TRANSACTION_FAILED_TIMEOUT,
+                        Collections.emptyList());
+            }
+
+            @Override
+            /* package */ void onQueryResponse(int result, List<NanoAppState> nanoAppStateList) {
+                try {
+                    onCompleteCallback.onQueryResponse(result, nanoAppStateList);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException while calling client onQueryComplete");
+                }
+            }
+        };
+    }
+
+    /**
+     * Adds a new transaction to the queue.
+     *
+     * If there was no pending transaction at the time, the transaction that was added will be
+     * started in this method.
+     *
+     * @param transaction the transaction to add
+     * @throws IllegalStateException if the queue is full
+     */
+    /* package */
+    synchronized void addTransaction(
+            ContextHubServiceTransaction transaction) throws IllegalStateException {
+        if (mTransactionQueue.size() == MAX_PENDING_REQUESTS) {
+            throw new IllegalStateException("Transaction transaction queue is full (capacity = "
+                    + MAX_PENDING_REQUESTS + ")");
+        }
+        mTransactionQueue.add(transaction);
+
+        if (mTransactionQueue.size() == 1) {
+            startNextTransaction();
+        }
+    }
+
+    /**
+     * Handles a transaction response from a Context Hub.
+     *
+     * @param transactionId the transaction ID of the response
+     * @param result        the result of the transaction
+     */
+    /* package */
+    synchronized void onTransactionResponse(int transactionId, int result) {
+        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+        if (transaction == null) {
+            Log.w(TAG, "Received unexpected transaction response (no transaction pending)");
+            return;
+        }
+        if (transaction.getTransactionId() != transactionId) {
+            Log.w(TAG, "Received unexpected transaction response (expected ID = "
+                    + transaction.getTransactionId() + ", received ID = " + transactionId + ")");
+            return;
+        }
+
+        transaction.onTransactionComplete(result);
+        removeTransactionAndStartNext();
+    }
+
+    /**
+     * Handles a query response from a Context Hub.
+     *
+     * @param nanoAppStateList the list of nanoapps included in the response
+     */
+    /* package */
+    synchronized void onQueryResponse(List<NanoAppState> nanoAppStateList) {
+        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+        if (transaction == null) {
+            Log.w(TAG, "Received unexpected query response (no transaction pending)");
+            return;
+        }
+        if (transaction.getTransactionType() != ContextHubTransaction.TYPE_QUERY_NANOAPPS) {
+            Log.w(TAG, "Received unexpected query response (expected " + transaction + ")");
+            return;
+        }
+
+        transaction.onQueryResponse(TransactionResult.SUCCESS, nanoAppStateList);
+        removeTransactionAndStartNext();
+    }
+
+    /**
+     * Handles a hub reset event by stopping a pending transaction and starting the next.
+     */
+    /* package */
+    synchronized void onHubReset() {
+        ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+        if (transaction == null) {
+            return;
+        }
+
+        removeTransactionAndStartNext();
+    }
+
+    /**
+     * Pops the front transaction from the queue and starts the next pending transaction request.
+     *
+     * Removing elements from the transaction queue must only be done through this method. When a
+     * pending transaction is removed, the timeout timer is cancelled and the transaction is marked
+     * complete.
+     *
+     * It is assumed that the transaction queue is non-empty when this method is invoked, and that
+     * the caller has obtained a lock on this ContextHubTransactionManager object.
+     */
+    private void removeTransactionAndStartNext() {
+        mTimeoutFuture.cancel(false /* mayInterruptIfRunning */);
+
+        ContextHubServiceTransaction transaction = mTransactionQueue.remove();
+        transaction.setComplete();
+
+        if (!mTransactionQueue.isEmpty()) {
+            startNextTransaction();
+        }
+    }
+
+    /**
+     * Starts the next pending transaction request.
+     *
+     * Starting new transactions must only be done through this method. This method continues to
+     * process the transaction queue as long as there are pending requests, and no transaction is
+     * pending.
+     *
+     * It is assumed that the caller has obtained a lock on this ContextHubTransactionManager
+     * object.
+     */
+    private void startNextTransaction() {
+        int result = Result.UNKNOWN_FAILURE;
+        while (result != Result.OK && !mTransactionQueue.isEmpty()) {
+            ContextHubServiceTransaction transaction = mTransactionQueue.peek();
+            result = transaction.onTransact();
+
+            if (result == Result.OK) {
+                Runnable onTimeoutFunc = () -> {
+                    synchronized (this) {
+                        if (!transaction.isComplete()) {
+                            Log.d(TAG, transaction + " timed out");
+                            transaction.onTimeout();
+
+                            removeTransactionAndStartNext();
+                        }
+                    }
+                };
+
+                long timeoutSeconds = transaction.getTimeout(TimeUnit.SECONDS);
+                mTimeoutFuture = mTimeoutExecutor.schedule(onTimeoutFunc, timeoutSeconds,
+                        TimeUnit.SECONDS);
+            } else {
+                mTransactionQueue.remove();
+            }
+        }
+    }
+}
index 36e9e7f..4a2da37 100644 (file)
@@ -23,7 +23,6 @@ LOCAL_SRC_FILES += \
     $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \
     $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \
-    $(LOCAL_REL_DIR)/com_android_server_location_ContextHubService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_location_GnssLocationProvider.cpp \
     $(LOCAL_REL_DIR)/com_android_server_locksettings_SyntheticPasswordManager.cpp \
     $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
deleted file mode 100644 (file)
index ad372de..0000000
+++ /dev/null
@@ -1,1201 +0,0 @@
-/*
- * Copyright 2016, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#undef LOG_NDEBUG
-#undef LOG_TAG
-#define LOG_NDEBUG 0
-#define LOG_TAG "ContextHubService"
-
-#include <inttypes.h>
-#include <jni.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/endian.h>
-
-#include <chrono>
-#include <mutex>
-#include <queue>
-#include <unordered_map>
-#include <utility>
-
-#include <android-base/macros.h>
-#include <android/hardware/contexthub/1.0/IContexthub.h>
-#include <cutils/log.h>
-
-#include "core_jni_helpers.h"
-#include <nativehelper/JNIHelp.h>
-
-using android::hardware::contexthub::V1_0::AsyncEventType;
-using android::hardware::contexthub::V1_0::ContextHub;
-using android::hardware::contexthub::V1_0::ContextHubMsg;
-using android::hardware::contexthub::V1_0::HubAppInfo;
-using android::hardware::contexthub::V1_0::IContexthub;
-using android::hardware::contexthub::V1_0::IContexthubCallback;
-using android::hardware::contexthub::V1_0::NanoAppBinary;
-using android::hardware::contexthub::V1_0::Result;
-using android::hardware::contexthub::V1_0::TransactionResult;
-
-using android::hardware::Return;
-
-using std::chrono::steady_clock;
-
-// If a transaction takes longer than this, we'll allow it to be
-// canceled by a new transaction.  Note we do _not_ automatically
-// cancel a transaction after this much time.  We can have a
-// legal transaction which takes longer than this amount of time,
-// as long as no other new transactions are attempted after this
-// time has expired.
-constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
-
-namespace android {
-
-constexpr uint32_t kNanoAppBinaryHeaderVersion = 1;
-
-// Important: this header is explicitly defined as little endian byte order, and
-// therefore may not match host endianness
-struct NanoAppBinaryHeader {
-    uint32_t headerVersion;        // 0x1 for this version
-    uint32_t magic;                // "NANO" (see NANOAPP_MAGIC in context_hub.h)
-    uint64_t appId;                // App Id, contains vendor id
-    uint32_t appVersion;           // Version of the app
-    uint32_t flags;                // Signed, encrypted
-    uint64_t hwHubType;            // Which hub type is this compiled for
-    uint8_t targetChreApiMajorVersion; // Which CHRE API version this is compiled for
-    uint8_t targetChreApiMinorVersion;
-    uint8_t reserved[6];
-} __attribute__((packed));
-
-enum HubMessageType {
-    CONTEXT_HUB_APPS_ENABLE  = 1, // Enables loaded nano-app(s)
-    CONTEXT_HUB_APPS_DISABLE = 2, // Disables loaded nano-app(s)
-    CONTEXT_HUB_LOAD_APP     = 3, // Load a supplied app
-    CONTEXT_HUB_UNLOAD_APP   = 4, // Unload a specified app
-    CONTEXT_HUB_QUERY_APPS   = 5, // Query for app(s) info on hub
-    CONTEXT_HUB_QUERY_MEMORY = 6, // Query for memory info
-    CONTEXT_HUB_OS_REBOOT    = 7, // Request to reboot context HUB OS
-};
-
-constexpr jint OS_APP_ID = -1;
-constexpr jint INVALID_APP_ID = -2;
-
-constexpr jint MIN_APP_ID = 1;
-constexpr jint MAX_APP_ID = 128;
-
-constexpr size_t MSG_HEADER_SIZE = 4;
-constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
-constexpr size_t HEADER_FIELD_MSG_VERSION = 1;
-constexpr size_t HEADER_FIELD_HUB_HANDLE = 2;
-constexpr size_t HEADER_FIELD_APP_INSTANCE = 3;
-
-constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
-constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
-constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
-
-jint getAppInstanceForAppId(uint64_t app_id);
-int onMessageReceipt(const uint32_t *header,
-                     size_t headerLen,
-                     const char *msg,
-                     size_t msgLen);
-void onHubReset(uint32_t hubId);
-void queryHubForApps(uint32_t hubId);
-void passOnOsResponse(uint32_t hubHandle,
-                      uint32_t msgType,
-                      TransactionResult result,
-                      const int8_t *additionalData,
-                      size_t additionalDataLen);
-
-bool closeLoadTxn(bool success, jint *appInstanceHandle);
-void closeUnloadTxn(bool success);
-int handleQueryAppsResponse(const std::vector<HubAppInfo> apps,
-                               uint32_t hubHandle);
-
-struct JniInfo {
-    JavaVM *vm;
-    jclass contextHubInfoClass;
-    jclass contextHubServiceClass;
-    jclass memoryRegionsClass;
-
-    jobject jContextHubService;
-
-    jmethodID msgReceiptCallBack;
-
-    jmethodID contextHubInfoCtor;
-    jmethodID contextHubInfoSetId;
-    jmethodID contextHubInfoSetName;
-    jmethodID contextHubInfoSetVendor;
-    jmethodID contextHubInfoSetToolchain;
-    jmethodID contextHubInfoSetPlatformVersion;
-    jmethodID contextHubInfoSetStaticSwVersion;
-    jmethodID contextHubInfoSetToolchainVersion;
-    jmethodID contextHubInfoSetPeakMips;
-    jmethodID contextHubInfoSetStoppedPowerDrawMw;
-    jmethodID contextHubInfoSetSleepPowerDrawMw;
-    jmethodID contextHubInfoSetPeakPowerDrawMw;
-    jmethodID contextHubInfoSetSupportedSensors;
-    jmethodID contextHubInfoSetMemoryRegions;
-    jmethodID contextHubInfoSetMaxPacketLenBytes;
-
-    jmethodID contextHubServiceMsgReceiptCallback;
-    jmethodID contextHubServiceAddAppInstance;
-    jmethodID contextHubServiceDeleteAppInstance;
-};
-
-
-
-class TxnManager {
-public:
-    TxnManager() {
-        mData = nullptr;
-        mIsPending = false;
-    }
-
-    ~TxnManager() {
-        closeTxn();
-    }
-
-    int addTxn(HubMessageType txnIdentifier, void *txnData) {
-        std::lock_guard<std::mutex>lock(mLock);
-        if (mIsPending) {
-            ALOGW("Transaction already found pending when trying to add a new one.");
-            return -1;
-        }
-        mIsPending = true;
-        mFirstTimeTxnCanBeCanceled = steady_clock::now() + kMinTransactionCancelTime;
-        mData = txnData;
-        mIdentifier = txnIdentifier;
-
-        return 0;
-    }
-
-    int closeTxn() {
-        std::lock_guard<std::mutex>lock(mLock);
-        closeTxnUnlocked();
-        return 0;
-    }
-
-    bool isTxnPending() {
-        std::lock_guard<std::mutex>lock(mLock);
-        return mIsPending;
-    }
-
-    void closeAnyStaleTxns() {
-        std::lock_guard<std::mutex>lock(mLock);
-        if (mIsPending && steady_clock::now() >= mFirstTimeTxnCanBeCanceled) {
-            ALOGW("Stale transaction canceled");
-            closeTxnUnlocked();
-        }
-    }
-
-    int fetchTxnData(HubMessageType *id, void **data) {
-        if (id == nullptr || data == nullptr) {
-            ALOGW("Null Params isNull{id, data} {%d, %d}",
-                  id == nullptr ? 1 : 0,
-                  data == nullptr ? 1 : 0);
-            return -1;
-        }
-
-        std::lock_guard<std::mutex>lock(mLock);
-        if (!mIsPending) {
-            ALOGW("No Transactions pending");
-            return -1;
-        }
-
-        *id = mIdentifier;
-        *data = mData;
-        return 0;
-    }
-
- private:
-    bool mIsPending;            // Is a transaction pending
-    std::mutex mLock;           // mutex for manager
-    HubMessageType mIdentifier; // What are we doing
-    void *mData;                // Details
-    steady_clock::time_point mFirstTimeTxnCanBeCanceled;
-
-    // Only call this if you hold the lock.
-    void closeTxnUnlocked() {
-        mIsPending = false;
-        free(mData);
-        mData = nullptr;
-    }
-};
-
-
-struct ContextHubServiceCallback : IContexthubCallback {
-    uint32_t mContextHubId;
-
-    ContextHubServiceCallback(uint32_t hubId) {
-        mContextHubId = hubId;
-    }
-
-    virtual Return<void> handleClientMsg(const ContextHubMsg &msg) {
-        jint appHandle = getAppInstanceForAppId(msg.appName);
-        if (appHandle < 0) {
-            ALOGE("Filtering out message due to invalid App Instance.");
-        } else {
-            uint32_t msgHeader[MSG_HEADER_SIZE] = {};
-            msgHeader[HEADER_FIELD_MSG_TYPE] = msg.msgType;
-            msgHeader[HEADER_FIELD_HUB_HANDLE] = mContextHubId;
-            msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle;
-            onMessageReceipt(msgHeader,
-                             MSG_HEADER_SIZE,
-                             reinterpret_cast<const char *>(msg.msg.data()),
-                             msg.msg.size());
-        }
-
-        return android::hardware::Void();
-    }
-
-    virtual Return<void> handleHubEvent(AsyncEventType evt) {
-        if (evt == AsyncEventType::RESTARTED) {
-            ALOGW("Context Hub handle %d restarted", mContextHubId);
-            onHubReset(mContextHubId);
-        } else {
-            ALOGW("Cannot handle event %u from hub %d", evt, mContextHubId);
-        }
-
-        return android::hardware::Void();
-    }
-
-    virtual Return<void> handleTxnResult(uint32_t txnId,
-                                         TransactionResult result) {
-        ALOGI("Handle transaction result , hubId %" PRIu32 ", txnId %" PRIu32 ", result %" PRIu32,
-              mContextHubId,
-              txnId,
-              result);
-
-        switch(txnId) {
-            case CONTEXT_HUB_APPS_ENABLE:
-            case CONTEXT_HUB_APPS_DISABLE:
-                passOnOsResponse(mContextHubId, txnId, result, nullptr, 0);
-                break;
-
-            case CONTEXT_HUB_UNLOAD_APP:
-                closeUnloadTxn(result == TransactionResult::SUCCESS);
-                passOnOsResponse(mContextHubId, txnId, result, nullptr, 0);
-                break;
-
-            case CONTEXT_HUB_LOAD_APP:
-                {
-                    jint appInstanceHandle = INVALID_APP_ID;
-                    bool appRunningOnHub = (result == TransactionResult::SUCCESS);
-                    if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
-                        if (appRunningOnHub) {
-                            // Now we're in an odd situation.  Our nanoapp
-                            // is up and running on the Context Hub.  However,
-                            // something went wrong in our Service code so that
-                            // we're not able to properly track this nanoapp
-                            // in our Service code.  If we tell the Java layer
-                            // things are good, it's a lie because the handle
-                            // we give them will fail when used with the Service.
-                            // If we tell the Java layer this failed, it's kind
-                            // of a lie as well, since this nanoapp is running.
-                            //
-                            // We leave a more robust fix for later, and for
-                            // now just tell the user things have failed.
-                            //
-                            // TODO(b/30835981): Make this situation better.
-                            result = TransactionResult::FAILURE;
-                        }
-                    }
-
-                    passOnOsResponse(mContextHubId,
-                                     txnId,
-                                     result,
-                                     reinterpret_cast<int8_t *>(&appInstanceHandle),
-                                     sizeof(appInstanceHandle));
-                    break;
-                }
-
-            default:
-                ALOGI("unrecognized transction id %" PRIu32, txnId);
-                break;
-        }
-        return android::hardware::Void();
-    }
-
-    virtual Return<void> handleAppsInfo(
-            const android::hardware::hidl_vec<HubAppInfo>& apps) {
-        TransactionResult result = TransactionResult::SUCCESS;
-        handleQueryAppsResponse(apps,mContextHubId);
-        passOnOsResponse(mContextHubId, CONTEXT_HUB_QUERY_APPS, result, nullptr, 0);
-        return android::hardware::Void();
-    }
-
-    virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode) {
-        ALOGI("Handle app aport called from %" PRIx64 " with abort code %" PRIu32,
-            appId,
-            abortCode);
-
-        // TODO: Plumb this to the clients interested in this app
-        return android::hardware::Void();
-    }
-
-    void setContextHubId(uint32_t id) {
-        mContextHubId = id;
-    }
-
-    uint32_t getContextHubId() {
-        return(mContextHubId);
-    }
-};
-
-struct AppInstanceInfo {
-    HubAppInfo appInfo;          // returned from the HAL
-    uint64_t truncName;          // Possibly truncated name for logging
-    uint32_t hubHandle;          // Id of the hub this app is on
-    jint instanceId;             // system wide unique instance id - assigned
-};
-
-struct ContextHubInfo {
-    int numHubs;
-    Vector<ContextHub> hubs;
-    sp<IContexthub> contextHub;
-};
-
-struct ContextHubServiceDb {
-    int initialized;
-    ContextHubInfo hubInfo;
-    JniInfo jniInfo;
-    std::queue<jint> freeIds;
-    std::unordered_map<jint, AppInstanceInfo> appInstances;
-    TxnManager txnManager;
-    std::vector<ContextHubServiceCallback *> regCallBacks;
-};
-
-ContextHubServiceDb db;
-
-bool getHubIdForHubHandle(int hubHandle, uint32_t *hubId) {
-    if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs || hubId == nullptr) {
-        return false;
-    } else {
-        *hubId = db.hubInfo.hubs[hubHandle].hubId;
-        return true;
-    }
-}
-
-int getHubHandleForAppInstance(jint id) {
-    if (!db.appInstances.count(id)) {
-        ALOGD("%s: Cannot find app for app instance %" PRId32,
-              __FUNCTION__,
-              id);
-        return -1;
-    }
-
-    return db.appInstances[id].hubHandle;
-}
-
-jint getAppInstanceForAppId(uint64_t app_id) {
-    auto end = db.appInstances.end();
-    for (auto current = db.appInstances.begin(); current != end; ++current) {
-        if (current->second.appInfo.appId == app_id) {
-            return current->first;
-        }
-    }
-    ALOGD("Cannot find app for app id %" PRIu64 ".", app_id);
-    return -1;
-}
-
-uint64_t getAppIdForAppInstance(jint id) {
-    if (!db.appInstances.count(id)) {
-        return INVALID_APP_ID;
-    }
-    return db.appInstances[id].appInfo.appId;
-}
-
-void queryHubForApps(uint32_t hubId) {
-    Result r = db.hubInfo.contextHub->queryApps(hubId);
-    ALOGD("Sent query for apps to hub %" PRIu32 " with result %" PRIu32, hubId, r);
-}
-
-void sendQueryForApps() {
-    for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
-        queryHubForApps(db.hubInfo.hubs[i].hubId);
-    }
-}
-
-int returnId(jint id) {
-    // Note : This method is not thread safe.
-    // id returned is guaranteed to be in use
-    if (id >= 0) {
-        db.freeIds.push(id);
-        return 0;
-    }
-
-    return -1;
-}
-
-jint generateId() {
-    // Note : This method is not thread safe.
-    jint retVal = -1;
-
-    if (!db.freeIds.empty()) {
-        retVal = db.freeIds.front();
-        db.freeIds.pop();
-    }
-
-    return retVal;
-}
-
-jint addAppInstance(const HubAppInfo *appInfo, uint32_t hubHandle,
-        jint appInstanceHandle, JNIEnv *env) {
-    // Not checking if the apps are indeed distinct
-    AppInstanceInfo entry;
-    assert(appInfo);
-
-
-    entry.appInfo = *appInfo;
-
-    entry.instanceId = appInstanceHandle;
-    entry.truncName = appInfo->appId;
-    entry.hubHandle = hubHandle;
-    db.appInstances[appInstanceHandle] = entry;
-    // Finally - let the service know of this app instance, to populate
-    // the Java cache.
-    env->CallIntMethod(db.jniInfo.jContextHubService,
-                       db.jniInfo.contextHubServiceAddAppInstance,
-                       hubHandle, entry.instanceId,
-                       entry.truncName,
-                       entry.appInfo.version);
-
-    const char *action = (db.appInstances.count(appInstanceHandle) == 0) ? "Added" : "Updated";
-    ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
-          " as appInstance %" PRId32, action, entry.truncName,
-          entry.hubHandle, appInstanceHandle);
-
-    return appInstanceHandle;
-}
-
-int deleteAppInstance(jint id, JNIEnv *env) {
-    bool fullyDeleted = true;
-
-    if (db.appInstances.count(id)) {
-        db.appInstances.erase(id);
-    } else {
-        ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
-        fullyDeleted = false;
-    }
-    returnId(id);
-
-    if ((env == nullptr) ||
-        (env->CallIntMethod(db.jniInfo.jContextHubService,
-                       db.jniInfo.contextHubServiceDeleteAppInstance,
-                       id) != 0)) {
-        ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
-        fullyDeleted = false;
-    }
-
-    if (fullyDeleted) {
-        ALOGI("Deleted App id : %" PRId32, id);
-        return 0;
-    }
-    return -1;
-}
-
-int startLoadAppTxn(uint64_t appId, int hubHandle) {
-    AppInstanceInfo *txnInfo = new AppInstanceInfo();
-    jint instanceId = generateId();
-
-    if (!txnInfo || instanceId < 0) {
-        returnId(instanceId);
-        delete txnInfo;
-        return -1;
-    }
-
-    txnInfo->truncName = appId;
-    txnInfo->hubHandle = hubHandle;
-    txnInfo->instanceId = instanceId;
-
-    txnInfo->appInfo.appId = appId;
-    txnInfo->appInfo.version = -1; // Awaited
-
-    if (db.txnManager.addTxn(CONTEXT_HUB_LOAD_APP, txnInfo) != 0) {
-        returnId(instanceId);
-        delete txnInfo;
-        return -1;
-    }
-
-    return 0;
-}
-
-int startUnloadAppTxn(jint appInstanceHandle) {
-    jint *txnData = new(jint);
-    if (!txnData) {
-        ALOGW("Cannot allocate memory to start unload transaction");
-        return -1;
-    }
-
-    *txnData = appInstanceHandle;
-
-    if (db.txnManager.addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) {
-        delete txnData;
-        ALOGW("Cannot start transaction to unload app");
-        return -1;
-    }
-
-    return 0;
-}
-
-void getHubsCb(const ::android::hardware::hidl_vec<ContextHub>& hubs)  {
-    for (size_t i = 0; i < hubs.size(); i++) {
-        db.hubInfo.hubs.push_back(hubs[i]);
-    }
-}
-
-void initContextHubService() {
-    db.hubInfo.numHubs = 0;
-
-    db.hubInfo.contextHub = IContexthub::getService();
-
-    if (db.hubInfo.contextHub == nullptr) {
-        ALOGE("Could not load context hub hal");
-    } else {
-        ALOGI("Loaded context hub hal, isRemote %s", db.hubInfo.contextHub->isRemote() ? "TRUE" : "FALSE");
-    }
-
-    // Prep for storing app info
-    for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
-        db.freeIds.push(i);
-    }
-
-    if (db.hubInfo.contextHub != nullptr) {
-        std::function<void(const ::android::hardware::hidl_vec<ContextHub>& hubs)> f = getHubsCb;
-        if(!db.hubInfo.contextHub->getHubs(f).isOk()) {
-            ALOGW("GetHubs Failed! transport error.");
-            return;
-        };
-
-        int retNumHubs = db.hubInfo.hubs.size();
-        ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
-        db.hubInfo.numHubs = retNumHubs;
-
-        for (int i = 0; i < db.hubInfo.numHubs; i++) {
-            ALOGI("Subscribing to hubHandle %d", i);
-
-            ContextHubServiceCallback *callBackPtr =
-                new ContextHubServiceCallback(db.hubInfo.hubs[i].hubId);
-            db.hubInfo.contextHub->registerCallback(db.hubInfo.hubs[i].hubId,
-                                                    callBackPtr);
-            db.regCallBacks.push_back(callBackPtr);
-        }
-
-        sendQueryForApps();
-
-    } else {
-        ALOGW("No Context Hub Module present");
-    }
-}
-
-void onHubReset(uint32_t hubId) {
-    TransactionResult result = TransactionResult::SUCCESS;
-    db.txnManager.closeTxn();
-    // TODO : Expose this through an api
-    passOnOsResponse(hubId, CONTEXT_HUB_OS_REBOOT, result, nullptr, 0);
-    queryHubForApps(hubId);
-}
-
-int onMessageReceipt(const uint32_t *header,
-                     size_t headerLen,
-                     const char *msg,
-                     size_t msgLen) {
-    JNIEnv *env;
-
-    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
-      return -1;
-    }
-
-    jbyteArray jmsg = env->NewByteArray(msgLen);
-    if (jmsg == nullptr) {
-        ALOGW("Can't allocate %zu byte array", msgLen);
-        return -1;
-    }
-    jintArray jheader = env->NewIntArray(headerLen);
-    if (jheader == nullptr) {
-        env->DeleteLocalRef(jmsg);
-        ALOGW("Can't allocate %zu int array", headerLen);
-        return -1;
-    }
-
-    env->SetByteArrayRegion(jmsg, 0, msgLen, reinterpret_cast<const jbyte *>(msg));
-    env->SetIntArrayRegion(jheader, 0, headerLen, reinterpret_cast<const jint *>(header));
-
-    int ret = (env->CallIntMethod(db.jniInfo.jContextHubService,
-                                  db.jniInfo.contextHubServiceMsgReceiptCallback,
-                                  jheader,
-                                  jmsg) != 0);
-    env->DeleteLocalRef(jmsg);
-    env->DeleteLocalRef(jheader);
-
-    return ret;
-}
-
-int handleQueryAppsResponse(const std::vector<HubAppInfo> apps,
-                               uint32_t hubHandle) {
-    JNIEnv *env;
-    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
-            return -1;
-    }
-
-    int numApps = apps.size();
-
-    // We use this information to sync our JNI and Java caches of nanoapp info.
-    // We want to accomplish two things here:
-    // 1) Remove entries from our caches which are stale, and pertained to
-    //    apps no longer running on Context Hub.
-    // 2) Populate our caches with the latest information of all these apps.
-
-    // We make a couple of assumptions here:
-    // A) The JNI and Java caches are in sync with each other (this isn't
-    //    necessarily true; any failure of a single call into Java land to
-    //    update its cache will leave that cache in a bad state.  For NYC,
-    //    we're willing to tolerate this for now).
-    // B) The total number of apps is relatively small, so horribly inefficent
-    //    algorithms aren't too painful.
-    // C) We're going to call this relatively infrequently, so its inefficency
-    //    isn't a big impact.
-
-
-    // (1).  Looking for stale cache entries.  Yes, this is O(N^2).  See
-    // assumption (B).  Per assumption (A), it is sufficient to iterate
-    // over just the JNI cache.
-    auto end = db.appInstances.end();
-    for (auto current = db.appInstances.begin(); current != end; ) {
-        AppInstanceInfo cacheEntry = current->second;
-        // We perform our iteration here because if we call
-        // delete_app_instance() below, it will erase() this entry.
-        current++;
-        bool entryIsStale = true;
-        for (int i = 0; i < numApps; i++) {
-            if (apps[i].appId == cacheEntry.appInfo.appId) {
-                // We found a match; this entry is current.
-                entryIsStale = false;
-                break;
-            }
-        }
-
-        if (entryIsStale) {
-            deleteAppInstance(cacheEntry.instanceId, env);
-        }
-    }
-
-    // (2).  Update our caches with the latest.
-    for (int i = 0; i < numApps; i++) {
-        // We will only have one instance of the app
-        // TODO : Change this logic once we support multiple instances of the same app
-        jint appInstance = getAppInstanceForAppId(apps[i].appId);
-        if (appInstance == -1) {
-            // This is a previously unknown app, let's allocate an "id" for it.
-            appInstance = generateId();
-        }
-        addAppInstance(&apps[i], hubHandle, appInstance, env);
-    }
-    return 0;
-}
-
-// TODO(b/30807327): Do not use raw bytes for additional data.  Use the
-//     JNI interfaces for the appropriate types.
-void passOnOsResponse(uint32_t hubHandle,
-                      uint32_t msgType,
-                      TransactionResult result,
-                      const int8_t *additionalData,
-                      size_t additionalDataLen) {
-    JNIEnv *env;
-
-    if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
-        ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32,
-              msgType);
-        return;
-    }
-
-    uint32_t header[MSG_HEADER_SIZE];
-    memset(header, 0, sizeof(header));
-
-    if (!additionalData) {
-        additionalDataLen = 0; // clamp
-    }
-    int msgLen = 1 + additionalDataLen;
-
-    int8_t *msg = new int8_t[msgLen];
-
-    if (!msg) {
-        ALOGW("Unexpected : Ran out of memory, cannot send response");
-        return;
-    }
-
-    header[HEADER_FIELD_MSG_TYPE] = msgType;
-    header[HEADER_FIELD_MSG_VERSION] = 0;
-    header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
-    header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
-
-    // Due to API constraints, at the moment we can't change the fact that
-    // we're changing our 4-byte response to a 1-byte value.  But we can prevent
-    // the possible change in sign (and thus meaning) that would happen from
-    // a naive cast.  Further, we can log when we're losing part of the value.
-    // TODO(b/30918279): Don't truncate this result.
-    int8_t truncatedResult;
-    truncatedResult = static_cast<int8_t>(result);
-    msg[0] = truncatedResult;
-
-    if (additionalData) {
-        memcpy(&msg[1], additionalData, additionalDataLen);
-    }
-
-    jbyteArray jmsg = env->NewByteArray(msgLen);
-    jintArray jheader = env->NewIntArray(arraysize(header));
-
-    env->SetByteArrayRegion(jmsg, 0, msgLen, reinterpret_cast<jbyte *>(msg));
-    env->SetIntArrayRegion(jheader, 0, arraysize(header), reinterpret_cast<jint *>(header));
-
-    ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
-          header[HEADER_FIELD_MSG_TYPE],
-          header[HEADER_FIELD_APP_INSTANCE],
-          header[HEADER_FIELD_HUB_HANDLE]);
-
-    env->CallIntMethod(db.jniInfo.jContextHubService,
-                       db.jniInfo.contextHubServiceMsgReceiptCallback,
-                       jheader,
-                       jmsg);
-
-    env->DeleteLocalRef(jmsg);
-    env->DeleteLocalRef(jheader);
-
-    delete[] msg;
-}
-
-void closeUnloadTxn(bool success) {
-    void *txnData = nullptr;
-    HubMessageType txnId;
-
-    if (success && db.txnManager.fetchTxnData(&txnId, &txnData) == 0 &&
-        txnId == CONTEXT_HUB_UNLOAD_APP) {
-        JNIEnv *env;
-        if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
-            ALOGW("Could not attach to JVM !");
-            env = nullptr;
-        }
-        jint handle = *reinterpret_cast<jint *>(txnData);
-        deleteAppInstance(handle, env);
-    } else {
-        ALOGW("Could not unload the app successfully ! success %d, txnData %p",
-              success,
-              txnData);
-    }
-
-    db.txnManager.closeTxn();
-}
-
-bool closeLoadTxn(bool success, jint *appInstanceHandle) {
-    void *txnData;
-    HubMessageType txnId;
-
-    if (success && db.txnManager.fetchTxnData(&txnId, &txnData) == 0 &&
-        txnId == CONTEXT_HUB_LOAD_APP) {
-        AppInstanceInfo *info = static_cast<AppInstanceInfo *>(txnData);
-        *appInstanceHandle = info->instanceId;
-
-        JNIEnv *env;
-        if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) {
-            addAppInstance(&info->appInfo, info->hubHandle, info->instanceId, env);
-        } else {
-            ALOGW("Could not attach to JVM !");
-            success = false;
-        }
-        // While we just called addAppInstance above, our info->appInfo was
-        // incomplete (for example, the 'version' is hardcoded to -1).  So we
-        // trigger an additional query to the CHRE, so we'll be able to get
-        // all the app "info", and have our JNI and Java caches with the
-        // full information.
-        sendQueryForApps();
-    } else {
-        ALOGW("Could not load the app successfully ! Unexpected failure");
-        *appInstanceHandle = INVALID_APP_ID;
-        success = false;
-    }
-
-    db.txnManager.closeTxn();
-    return success;
-}
-
-int initJni(JNIEnv *env, jobject instance) {
-    if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
-        return -1;
-    }
-
-    db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
-
-    db.jniInfo.contextHubInfoClass =
-            env->FindClass("android/hardware/location/ContextHubInfo");
-    db.jniInfo.contextHubServiceClass =
-            env->FindClass("com/android/server/location/ContextHubService");
-
-    db.jniInfo.memoryRegionsClass =
-            env->FindClass("android/hardware/location/MemoryRegion");
-
-    db.jniInfo.contextHubInfoCtor =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
-    db.jniInfo.contextHubInfoSetId =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
-    db.jniInfo.contextHubInfoSetName =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName", "(Ljava/lang/String;)V");
-    db.jniInfo.contextHubInfoSetVendor =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setVendor",
-                             "(Ljava/lang/String;)V");
-    db.jniInfo.contextHubInfoSetToolchain =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setToolchain",
-                             "(Ljava/lang/String;)V");
-    db.jniInfo.contextHubInfoSetPlatformVersion =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setPlatformVersion",
-                             "(I)V");
-    db.jniInfo.contextHubInfoSetStaticSwVersion =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setStaticSwVersion",
-                             "(I)V");
-    db.jniInfo.contextHubInfoSetToolchainVersion =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setToolchainVersion",
-                             "(I)V");
-    db.jniInfo.contextHubInfoSetPeakMips =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setPeakMips",
-                             "(F)V");
-    db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setStoppedPowerDrawMw",
-                             "(F)V");
-    db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setSleepPowerDrawMw",
-                             "(F)V");
-    db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setPeakPowerDrawMw",
-                             "(F)V");
-    db.jniInfo.contextHubInfoSetSupportedSensors =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setSupportedSensors",
-                             "([I)V");
-    db.jniInfo.contextHubInfoSetMemoryRegions =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setMemoryRegions",
-                             "([Landroid/hardware/location/MemoryRegion;)V");
-    db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
-             env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                              "setMaxPacketLenBytes",
-                              "(I)V");
-    db.jniInfo.contextHubServiceMsgReceiptCallback =
-            env->GetMethodID(db.jniInfo.contextHubServiceClass,
-                             "onMessageReceipt",
-                             "([I[B)I");
-    db.jniInfo.contextHubInfoSetName =
-            env->GetMethodID(db.jniInfo.contextHubInfoClass,
-                             "setName",
-                             "(Ljava/lang/String;)V");
-    db.jniInfo.contextHubServiceAddAppInstance =
-                 env->GetMethodID(db.jniInfo.contextHubServiceClass,
-                                  "addAppInstance",
-                                  "(IIJI)I");
-    db.jniInfo.contextHubServiceDeleteAppInstance =
-                 env->GetMethodID(db.jniInfo.contextHubServiceClass,
-                                  "deleteAppInstance",
-                                  "(I)I");
-
-    return 0;
-}
-
-jobject constructJContextHubInfo(JNIEnv *env, const ContextHub &hub) {
-    jstring jstrBuf;
-    jintArray jintBuf;
-    jobjectArray jmemBuf;
-
-    jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
-                                  db.jniInfo.contextHubInfoCtor);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub.hubId);
-
-    jstrBuf = env->NewStringUTF(hub.name.c_str());
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
-    env->DeleteLocalRef(jstrBuf);
-
-    jstrBuf = env->NewStringUTF(hub.vendor.c_str());
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
-    env->DeleteLocalRef(jstrBuf);
-
-    jstrBuf = env->NewStringUTF(hub.toolchain.c_str());
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
-    env->DeleteLocalRef(jstrBuf);
-
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub.platformVersion);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub.toolchainVersion);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub.peakMips);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
-                        hub.stoppedPowerDrawMw);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
-                        hub.sleepPowerDrawMw);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
-                        hub.peakPowerDrawMw);
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
-                        hub.maxSupportedMsgLen);
-
-
-    jintBuf = env->NewIntArray(hub.connectedSensors.size());
-    int *connectedSensors = new int[hub.connectedSensors.size()];
-
-    if (!connectedSensors) {
-      ALOGW("Cannot allocate memory! Unexpected");
-      assert(false);
-    } else {
-      for (unsigned int i = 0; i < hub.connectedSensors.size(); i++) {
-        // TODO :: Populate connected sensors.
-        //connectedSensors[i] = hub.connectedSensors[i].sensorType;
-        connectedSensors[i] = 0;
-      }
-    }
-
-    env->SetIntArrayRegion(jintBuf, 0, hub.connectedSensors.size(),
-                           connectedSensors);
-
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
-    env->DeleteLocalRef(jintBuf);
-
-    // We are not getting the memory regions from the CH Hal - change this when it is available
-    jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
-    // Note the zero size above. We do not need to set any elements
-    env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
-    env->DeleteLocalRef(jmemBuf);
-
-
-    delete[] connectedSensors;
-    return jHub;
-}
-
-jobjectArray nativeInitialize(JNIEnv *env, jobject instance) {
-    jobject hub;
-    jobjectArray retArray;
-
-    if (initJni(env, instance) < 0) {
-        return nullptr;
-    }
-
-    initContextHubService();
-
-    if (db.hubInfo.numHubs > 1) {
-        ALOGW("Clamping the number of hubs to 1");
-        db.hubInfo.numHubs = 1;
-    }
-
-    retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
-
-    for(int i = 0; i < db.hubInfo.numHubs; i++) {
-        hub = constructJContextHubInfo(env, db.hubInfo.hubs[i]);
-        env->SetObjectArrayElement(retArray, i, hub);
-    }
-
-    return retArray;
-}
-
-Result sendLoadNanoAppRequest(uint32_t hubId,
-                              jbyte *data,
-                              size_t dataBufferLength) {
-    auto header = reinterpret_cast<const NanoAppBinaryHeader *>(data);
-    Result result;
-
-    if (dataBufferLength < sizeof(NanoAppBinaryHeader)) {
-        ALOGE("Got short NanoApp, length %zu", dataBufferLength);
-        result = Result::BAD_PARAMS;
-    } else if (header->headerVersion != htole32(kNanoAppBinaryHeaderVersion)) {
-        ALOGE("Got unexpected NanoApp header version %" PRIu32,
-              letoh32(header->headerVersion));
-        result = Result::BAD_PARAMS;
-    } else {
-        NanoAppBinary nanoapp;
-
-        // Data from the common nanoapp header goes into explicit fields
-        nanoapp.appId      = letoh64(header->appId);
-        nanoapp.appVersion = letoh32(header->appVersion);
-        nanoapp.flags      = letoh32(header->flags);
-        nanoapp.targetChreApiMajorVersion = header->targetChreApiMajorVersion;
-        nanoapp.targetChreApiMinorVersion = header->targetChreApiMinorVersion;
-
-        // Everything past the header goes in customBinary
-        auto dataBytes = reinterpret_cast<const uint8_t *>(data);
-        std::vector<uint8_t> customBinary(
-            dataBytes + sizeof(NanoAppBinaryHeader),
-            dataBytes + dataBufferLength);
-        nanoapp.customBinary = std::move(customBinary);
-
-        ALOGW("Calling Load NanoApp on hub %d", hubId);
-        result = db.hubInfo.contextHub->loadNanoApp(hubId,
-                                                    nanoapp,
-                                                    CONTEXT_HUB_LOAD_APP);
-    }
-
-    return result;
-}
-
-jint nativeSendMessage(JNIEnv *env,
-                       jobject instance,
-                       jintArray header_,
-                       jbyteArray data_) {
-    // With the new binderized HAL definition, this function can be made much simpler.
-    // All the magic can be removed. This is not however needed for the default implementation
-    // TODO :: Change the JNI interface to conform to the new HAL interface and clean up this
-    // function
-    jint retVal = -1; // Default to failure
-
-    jint *header = env->GetIntArrayElements(header_, 0);
-    size_t numHeaderElements = env->GetArrayLength(header_);
-    jbyte *data = env->GetByteArrayElements(data_, 0);
-    size_t dataBufferLength = env->GetArrayLength(data_);
-
-    if (numHeaderElements < MSG_HEADER_SIZE) {
-        ALOGW("Malformed header len");
-        return -1;
-    }
-
-    jint appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
-    uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
-    int hubHandle = -1;
-    uint64_t appId;
-
-    if (msgType == CONTEXT_HUB_UNLOAD_APP) {
-        hubHandle = getHubHandleForAppInstance(appInstanceHandle);
-    } else if (msgType == CONTEXT_HUB_LOAD_APP) {
-        if (numHeaderElements < MSG_HEADER_SIZE_LOAD_APP) {
-            return -1;
-        }
-        uint64_t appIdLo = header[HEADER_FIELD_LOAD_APP_ID_LO];
-        uint64_t appIdHi = header[HEADER_FIELD_LOAD_APP_ID_HI];
-        appId = appIdHi << 32 | appIdLo;
-
-        hubHandle = header[HEADER_FIELD_HUB_HANDLE];
-    } else {
-        hubHandle = header[HEADER_FIELD_HUB_HANDLE];
-    }
-
-    uint32_t hubId = -1;
-    if (!getHubIdForHubHandle(hubHandle, &hubId)) {
-        ALOGD("Invalid hub Handle %d", hubHandle);
-        return -1;
-    }
-
-    if (msgType == CONTEXT_HUB_LOAD_APP ||
-        msgType == CONTEXT_HUB_UNLOAD_APP) {
-
-        db.txnManager.closeAnyStaleTxns();
-
-        if (db.txnManager.isTxnPending()) {
-            // TODO : There is a race conditio
-            ALOGW("Cannot load or unload app while a transaction is pending !");
-            return -1;
-        } else if (msgType == CONTEXT_HUB_LOAD_APP) {
-            if (startLoadAppTxn(appId, hubHandle) != 0) {
-                ALOGW("Cannot Start Load Transaction");
-                return -1;
-            }
-        } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
-            if (startUnloadAppTxn(appInstanceHandle) != 0) {
-                ALOGW("Cannot Start UnLoad Transaction");
-                return -1;
-            }
-        }
-    }
-
-    Result result;
-
-    if (msgType == CONTEXT_HUB_UNLOAD_APP) {
-        ALOGW("Calling UnLoad NanoApp for app %" PRIx64 " on hub %" PRIu32,
-              db.appInstances[appInstanceHandle].appInfo.appId,
-              hubId);
-        result = db.hubInfo.contextHub->unloadNanoApp(
-                hubId, db.appInstances[appInstanceHandle].appInfo.appId, CONTEXT_HUB_UNLOAD_APP);
-    } else {
-        if (appInstanceHandle == OS_APP_ID) {
-            if (msgType == CONTEXT_HUB_LOAD_APP) {
-                result = sendLoadNanoAppRequest(hubId, data, dataBufferLength);
-            } else if (msgType == CONTEXT_HUB_QUERY_APPS) {
-                result = db.hubInfo.contextHub->queryApps(hubId);
-            } else {
-                ALOGD("Dropping OS addresses message of type - %" PRIu32, msgType);
-                result = Result::BAD_PARAMS;
-            }
-        } else {
-            appId = getAppIdForAppInstance(appInstanceHandle);
-            if (appId == static_cast<uint64_t>(INVALID_APP_ID)) {
-                ALOGD("Cannot find application instance %d", appInstanceHandle);
-                result = Result::BAD_PARAMS;
-            } else if (hubHandle != getHubHandleForAppInstance(appInstanceHandle)) {
-                ALOGE("Given hubHandle (%d) doesn't match expected for app instance (%d)",
-                      hubHandle,
-                      getHubHandleForAppInstance(appInstanceHandle));
-                result = Result::BAD_PARAMS;
-            } else {
-                ContextHubMsg msg;
-                msg.appName = appId;
-                msg.msgType = msgType;
-                msg.msg.setToExternal((unsigned char *)data, dataBufferLength);
-
-                ALOGW("Sending msg of type %" PRIu32 " len %zu to app %" PRIx64 " on hub %" PRIu32,
-                       msgType,
-                       dataBufferLength,
-                       appId,
-                       hubId);
-                result = db.hubInfo.contextHub->sendMessageToHub(hubId, msg);
-            }
-        }
-    }
-
-    if (result != Result::OK) {
-        ALOGD("Send Message failure - %d", result);
-        if (msgType == CONTEXT_HUB_LOAD_APP) {
-            jint ignored;
-            closeLoadTxn(false, &ignored);
-        } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
-            closeUnloadTxn(false);
-        }
-    } else {
-        retVal = 0;
-    }
-
-    env->ReleaseIntArrayElements(header_, header, 0);
-    env->ReleaseByteArrayElements(data_, data, 0);
-
-    return retVal;
-}
-
-//--------------------------------------------------------------------------------------------------
-//
-const JNINativeMethod gContextHubServiceMethods[] = {
-    {"nativeInitialize",
-            "()[Landroid/hardware/location/ContextHubInfo;",
-            reinterpret_cast<void*>(nativeInitialize)},
-    {"nativeSendMessage",
-            "([I[B)I",
-            reinterpret_cast<void*>(nativeSendMessage)}
-};
-
-int register_android_server_location_ContextHubService(JNIEnv *env)
-{
-    RegisterMethodsOrDie(env, "com/android/server/location/ContextHubService",
-            gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
-
-    return 0;
-}
-
-}//namespace android
index 2f45181..46d5043 100644 (file)
@@ -39,7 +39,6 @@ int register_android_server_UsbMidiDevice(JNIEnv* env);
 int register_android_server_UsbHostManager(JNIEnv* env);
 int register_android_server_vr_VrManagerService(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
-int register_android_server_location_ContextHubService(JNIEnv* env);
 int register_android_server_location_GnssLocationProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_connectivity_tethering_OffloadHardwareInterface(JNIEnv*);
@@ -82,7 +81,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
     register_android_server_vr_VrManagerService(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
-    register_android_server_location_ContextHubService(env);
     register_android_server_location_GnssLocationProvider(env);
     register_android_server_connectivity_Vpn(env);
     register_android_server_connectivity_tethering_OffloadHardwareInterface(env);