Merge changes Id0ece760,I160b5a62,I8b7563d0
* changes:
Creates utility functions to convert between messages
Removes setters from ContextHubInfo
Replace JNI code with Java HIDL at ContextHubService
diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java
index 7fc7836..e1137aa 100644
--- a/core/java/android/hardware/location/ContextHubInfo.java
+++ b/core/java/android/hardware/location/ContextHubInfo.java
@@ -48,8 +48,7 @@
private MemoryRegion[] mMemoryRegions;
/*
- * TODO(b/66965339): Deprecate this constructor and the setter methods, and mark private fields
- * as final when the ContextHubService JNI code is removed.
+ * TODO(b/67734082): Deprecate this constructor and mark private fields as final.
*/
public ContextHubInfo() {
}
@@ -89,17 +88,6 @@
}
/**
- * set the context hub unique identifer
- *
- * @param bytes - Maximum number of bytes per message
- *
- * @hide
- */
- public void setMaxPacketLenBytes(int bytes) {
- mMaxPacketLengthBytes = bytes;
- }
-
- /**
* get the context hub unique identifer
*
* @return int - unique system wide identifier
@@ -109,17 +97,6 @@
}
/**
- * set the context hub unique identifer
- *
- * @param id - unique system wide identifier for the hub
- *
- * @hide
- */
- public void setId(int id) {
- mId = id;
- }
-
- /**
* get a string as a hub name
*
* @return String - a name for the hub
@@ -129,17 +106,6 @@
}
/**
- * set a string as the hub name
- *
- * @param name - the name for the hub
- *
- * @hide
- */
- public void setName(String name) {
- mName = name;
- }
-
- /**
* get a string as the vendor name
*
* @return String - a name for the vendor
@@ -149,17 +115,6 @@
}
/**
- * set a string as the vendor name
- *
- * @param vendor - a name for the vendor
- *
- * @hide
- */
- public void setVendor(String vendor) {
- mVendor = vendor;
- }
-
- /**
* get tool chain string
*
* @return String - description of the tool chain
@@ -169,17 +124,6 @@
}
/**
- * set tool chain string
- *
- * @param toolchain - description of the tool chain
- *
- * @hide
- */
- public void setToolchain(String toolchain) {
- mToolchain = toolchain;
- }
-
- /**
* get platform version
*
* @return int - platform version number
@@ -189,17 +133,6 @@
}
/**
- * set platform version
- *
- * @param platformVersion - platform version number
- *
- * @hide
- */
- public void setPlatformVersion(int platformVersion) {
- mPlatformVersion = platformVersion;
- }
-
- /**
* get static platform version number
*
* @return int - platform version number
@@ -209,15 +142,6 @@
}
/**
- * set platform software version
- *
- * @param staticSwVersion - platform static s/w version number
- *
- * @hide
- */
- public void setStaticSwVersion(int staticSwVersion) {}
-
- /**
* get the tool chain version
*
* @return int - the tool chain version
@@ -227,17 +151,6 @@
}
/**
- * set the tool chain version number
- *
- * @param toolchainVersion - tool chain version number
- *
- * @hide
- */
- public void setToolchainVersion(int toolchainVersion) {
- mToolchainVersion = toolchainVersion;
- }
-
- /**
* get the peak processing mips the hub can support
*
* @return float - peak MIPS that this hub can deliver
@@ -247,17 +160,6 @@
}
/**
- * set the peak mips that this hub can support
- *
- * @param peakMips - peak mips this hub can deliver
- *
- * @hide
- */
- public void setPeakMips(float peakMips) {
- mPeakMips = peakMips;
- }
-
- /**
* get the stopped power draw in milliwatts
* This assumes that the hub enter a stopped state - which is
* different from the sleep state. Latencies on exiting the
@@ -271,17 +173,6 @@
}
/**
- * Set the power consumed by the hub in stopped state
- *
- * @param stoppedPowerDrawMw - stopped power in milli watts
- *
- * @hide
- */
- public void setStoppedPowerDrawMw(float stoppedPowerDrawMw) {
- mStoppedPowerDrawMw = stoppedPowerDrawMw;
- }
-
- /**
* get the power draw of the hub in sleep mode. This assumes
* that the hub supports a sleep mode in which the power draw is
* lower than the power consumed when the hub is actively
@@ -297,17 +188,6 @@
}
/**
- * Set the sleep power draw in milliwatts
- *
- * @param sleepPowerDrawMw - sleep power draw in milliwatts.
- *
- * @hide
- */
- public void setSleepPowerDrawMw(float sleepPowerDrawMw) {
- mSleepPowerDrawMw = sleepPowerDrawMw;
- }
-
- /**
* get the peak powe draw of the hub. This is the power consumed
* by the hub at maximum load.
*
@@ -318,18 +198,6 @@
}
/**
- * set the peak power draw of the hub
- *
- * @param peakPowerDrawMw - peak power draw of the hub in
- * milliwatts.
- *
- * @hide
- */
- public void setPeakPowerDrawMw(float peakPowerDrawMw) {
- mPeakPowerDrawMw = peakPowerDrawMw;
- }
-
- /**
* get the sensors supported by this hub
*
* @return int[] - all the supported sensors on this hub
@@ -352,30 +220,6 @@
}
/**
- * set the supported sensors on this hub
- *
- * @param supportedSensors - supported sensors on this hub
- *
- * @hide
- */
- public void setSupportedSensors(int[] supportedSensors) {
- mSupportedSensors = Arrays.copyOf(supportedSensors, supportedSensors.length);
- }
-
- /**
- * set memory regions for this hub
- *
- * @param memoryRegions - memory regions information
- *
- * @see MemoryRegion
- *
- * @hide
- */
- public void setMemoryRegions(MemoryRegion[] memoryRegions) {
- mMemoryRegions = Arrays.copyOf(memoryRegions, memoryRegions.length);
- }
-
- /**
* @return the CHRE platform ID as defined in chre/version.h
*
* TODO(b/67734082): Expose as public API
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 633bb3e..3d81baf 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -43,7 +43,8 @@
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
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index 5e9f355..da481a8 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -18,15 +18,25 @@
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.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 @@
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";
+ + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
- public static final int ANY_HUB = -1;
- public static final int MSG_LOAD_NANO_APP = 3;
+ /*
+ * 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 @@
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 @@
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;
+ // Create an internal IContextHubTransactionCallback for the old API clients
+ NanoAppBinary nanoAppBinary = new NanoAppBinary(app.getAppBinary());
+ IContextHubTransactionCallback onCompleteCallback =
+ createLoadTransactionCallback(contextHubId, nanoAppBinary);
- long appId = app.getAppId();
+ ContextHubServiceTransaction transaction = mTransactionManager.createLoadTransaction(
+ contextHubId, nanoAppBinary, onCompleteCallback);
- msgHeader[HEADER_FIELD_LOAD_APP_ID_LO] = (int)(appId & 0xFFFFFFFF);
- msgHeader[HEADER_FIELD_LOAD_APP_ID_HI] = (int)((appId >> 32) & 0xFFFFFFFF);
-
- 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 @@
@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;
+ int contextHubId = info.getContexthubId();
+ long nanoAppId = info.getAppId();
+ IContextHubTransactionCallback onCompleteCallback =
+ createUnloadTransactionCallback(contextHubId, nanoAppId);
+ ContextHubServiceTransaction transaction = mTransactionManager.createUnloadTransaction(
+ contextHubId, nanoAppId, onCompleteCallback);
- byte msg[] = new byte[0];
-
- 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 @@
@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 @@
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 @@
return retArray;
}
- @Override
- public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
- throws RemoteException {
- checkPermissions();
+ /**
+ * 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;
+ }
- if (msg == null || msg.getData() == null) {
- Log.w(TAG, "null ptr");
+ 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 {
+ checkPermissions();
+ 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[] 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();
+ 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);
- return nativeSendMessage(msgHeader, msg.getData());
+ 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;
+ }
+ }
+
+ return (result == Result.OK ? 0 : -1);
+ }
+
+ /**
+ * 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 @@
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 @@
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 @@
}
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
index 0000000..66145bb
--- /dev/null
+++ b/services/core/java/com/android/server/location/ContextHubServiceTransaction.java
@@ -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
index 0000000..ddbaf86
--- /dev/null
+++ b/services/core/java/com/android/server/location/ContextHubServiceUtil.java
@@ -0,0 +1,168 @@
+/*
+ * 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.ContextHubMsg;
+import android.hardware.contexthub.V1_0.HostEndPoint;
+import android.hardware.contexthub.V1_0.HubAppInfo;
+import android.hardware.location.ContextHubInfo;
+import android.hardware.location.NanoAppBinary;
+import android.hardware.location.NanoAppMessage;
+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;
+ }
+
+ /**
+ * Creates a HIDL ContextHubMsg object to send to a nanoapp.
+ *
+ * @param hostEndPoint the ID of the client sending the message
+ * @param message the client-facing NanoAppMessage object describing the message
+ * @return the HIDL ContextHubMsg object
+ */
+ /* package */
+ static ContextHubMsg createHidlContextHubMessage(short hostEndPoint, NanoAppMessage message) {
+ ContextHubMsg hidlMessage = new ContextHubMsg();
+
+ hidlMessage.appName = message.getNanoAppId();
+ hidlMessage.hostEndPoint = hostEndPoint;
+ hidlMessage.msgType = message.getMessageType();
+ copyToByteArrayList(message.getMessageBody(), hidlMessage.msg);
+
+ return hidlMessage;
+ }
+
+ /**
+ * Creates a client-facing NanoAppMessage object to send to a client.
+ *
+ * @param message the HIDL ContextHubMsg object from a nanoapp
+ * @return the NanoAppMessage object
+ */
+ /* package */
+ static NanoAppMessage createNanoAppMessage(ContextHubMsg message) {
+ byte[] messageArray = createPrimitiveByteArray(message.msg);
+
+ return NanoAppMessage.createMessageFromNanoApp(
+ message.appName, message.msgType, messageArray,
+ message.hostEndPoint == HostEndPoint.BROADCAST);
+ }
+}
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
index 0000000..898b76c
--- /dev/null
+++ b/services/core/java/com/android/server/location/ContextHubTransactionManager.java
@@ -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();
+ }
+ }
+ }
+}
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 36e9e7f..4a2da37 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -23,7 +23,6 @@
$(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
index ad372de..0000000
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ /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
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 2f45181..46d5043 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -39,7 +39,6 @@
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 @@
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);