From b741e3b374e7eebf96e2104dec5caccf723b2a39 Mon Sep 17 00:00:00 2001 From: Ashutosh Joshi Date: Tue, 29 Mar 2016 09:19:56 -0700 Subject: [PATCH] Added handling apps query response from context hub Added handling of app query reponse from context hub. Exposed the maximum message size to clients. Change-Id: Ie96a860774d005ad6ad72acc88dc79964835486b --- api/system-current.txt | 18 +- .../hardware/location/ContextHubInfo.java | 24 +- .../hardware/location/ContextHubManager.java | 46 +- .../hardware/location/ContextHubMessage.java | 11 +- .../hardware/location/ContextHubService.java | 151 ++++-- .../hardware/location/NanoAppFilter.java | 16 +- .../location/NanoAppInstanceInfo.java | 33 +- ...id_hardware_location_ContextHubService.cpp | 451 +++++++++++++++--- 8 files changed, 578 insertions(+), 172 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index e1e73e93aaccb..fe562bb9014f2 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -15271,6 +15271,7 @@ package android.hardware.location { ctor public ContextHubInfo(); method public int describeContents(); method public int getId(); + method public int getMaxPacketLengthBytes(); method public android.hardware.location.MemoryRegion[] getMemoryRegions(); method public java.lang.String getName(); method public float getPeakMips(); @@ -15298,10 +15299,6 @@ package android.hardware.location { method public int sendMessage(int, int, android.hardware.location.ContextHubMessage); method public int unloadNanoApp(int); method public int unregisterCallback(android.hardware.location.ContextHubManager.Callback); - field public static final int ANY_HUB = -1; // 0xffffffff - field public static final int MSG_DATA_SEND = 3; // 0x3 - field public static final int MSG_LOAD_NANO_APP = 1; // 0x1 - field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2 } public static abstract class ContextHubManager.Callback { @@ -15495,7 +15492,7 @@ package android.hardware.location { public class NanoAppInstanceInfo { ctor public NanoAppInstanceInfo(); method public int describeContents(); - method public int getAppId(); + method public long getAppId(); method public int getAppVersion(); method public int getContexthubId(); method public int getHandle(); @@ -15506,17 +15503,6 @@ package android.hardware.location { method public int getNeededWriteMemBytes(); method public int[] getOutputEvents(); method public java.lang.String getPublisher(); - method public void setAppId(int); - method public void setAppVersion(int); - method public void setContexthubId(int); - method public void setHandle(int); - method public void setName(java.lang.String); - method public void setNeededExecMemBytes(int); - method public void setNeededReadMemBytes(int); - method public void setNeededSensors(int[]); - method public void setNeededWriteMemBytes(int); - method public void setOutputEvents(int[]); - method public void setPublisher(java.lang.String); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/java/android/hardware/location/ContextHubInfo.java b/core/java/android/hardware/location/ContextHubInfo.java index 644e29fcaedfe..ae44f1d68c3cb 100644 --- a/core/java/android/hardware/location/ContextHubInfo.java +++ b/core/java/android/hardware/location/ContextHubInfo.java @@ -37,6 +37,7 @@ public class ContextHubInfo { private float mStoppedPowerDrawMw; private float mSleepPowerDrawMw; private float mPeakPowerDrawMw; + private int mMaxPacketLengthBytes; private int[] mSupportedSensors; @@ -45,6 +46,27 @@ public class ContextHubInfo { public ContextHubInfo() { } + /** + * returns the maximum number of bytes that can be sent per message to the hub + * + * @return int - maximum bytes that can be transmitted in a + * single packet + */ + public int getMaxPacketLengthBytes() { + return mMaxPacketLengthBytes; + } + + /** + * 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 * @@ -374,4 +396,4 @@ public class ContextHubInfo { return new ContextHubInfo[size]; } }; -} +} \ No newline at end of file diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java index 4ddf7673b58ca..89edaa9780f6c 100644 --- a/core/java/android/hardware/location/ContextHubManager.java +++ b/core/java/android/hardware/location/ContextHubManager.java @@ -42,23 +42,6 @@ public final class ContextHubManager { private Callback mCallback; private Handler mCallbackHandler; - /** - * A special context hub identifier meaning any possible hub on the system. - */ - public static final int ANY_HUB = -1; - /** - * A constant denoting a message to load a a Nano App - */ - public static final int MSG_LOAD_NANO_APP = 1; - /** - * A constant denoting a message to unload a a Nano App - */ - public static final int MSG_UNLOAD_NANO_APP = 2; - /** - * A constant denoting a message to send a message - */ - public static final int MSG_DATA_SEND = 3; - /** * An interface to receive asynchronous communication from the context hub. */ @@ -69,7 +52,7 @@ public final class ContextHubManager { * Callback function called on message receipt from context hub. * * @param hubHandle Handle (system-wide unique identifier) of the hub of the message. - * @param nanoAppHandle Handle (unique identifier) for the app that sent the message. + * @param nanoAppHandle Handle (unique identifier) for app instance that sent the message. * @param message The context hub message. * * @see ContextHubMessage @@ -89,7 +72,7 @@ public final class ContextHubManager { try { retVal = getBinder().getContextHubHandles(); } catch (RemoteException e) { - Log.e(TAG, "Could not fetch context hub handles : " + e); + Log.w(TAG, "Could not fetch context hub handles : " + e); } return retVal; } @@ -107,7 +90,7 @@ public final class ContextHubManager { try { retVal = getBinder().getContextHubInfo(hubHandle); } catch (RemoteException e) { - Log.e(TAG, "Could not fetch context hub info :" + e); + Log.w(TAG, "Could not fetch context hub info :" + e); } return retVal; @@ -126,6 +109,7 @@ public final class ContextHubManager { */ public int loadNanoApp(int hubHandle, NanoApp app) { int retVal = -1; + if (app == null) { return retVal; } @@ -133,7 +117,7 @@ public final class ContextHubManager { try { retVal = getBinder().loadNanoApp(hubHandle, app); } catch (RemoteException e) { - Log.e(TAG, "Could not fetch load nanoApp :" + e); + Log.w(TAG, "Could not load nanoApp :" + e); } return retVal; @@ -152,7 +136,7 @@ public final class ContextHubManager { try { retVal = getBinder().unloadNanoApp(nanoAppHandle); } catch (RemoteException e) { - Log.e(TAG, "Could not fetch unload nanoApp :" + e); + Log.w(TAG, "Could not fetch unload nanoApp :" + e); } return retVal; @@ -172,7 +156,7 @@ public final class ContextHubManager { try { retVal = getBinder().getNanoAppInstanceInfo(nanoAppHandle); } catch (RemoteException e) { - Log.e(TAG, "Could not fetch nanoApp info :" + e); + Log.w(TAG, "Could not fetch nanoApp info :" + e); } return retVal; @@ -193,7 +177,7 @@ public final class ContextHubManager { try { retVal = getBinder().findNanoAppOnHub(hubHandle, filter); } catch (RemoteException e) { - Log.e(TAG, "Could not query nanoApp instance :" + e); + Log.w(TAG, "Could not query nanoApp instance :" + e); } return retVal; } @@ -212,10 +196,14 @@ public final class ContextHubManager { public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage message) { int retVal = -1; + if (message == null || message.getData() == null) { + Log.w(TAG, "null ptr"); + return retVal; + } try { retVal = getBinder().sendMessage(hubHandle, nanoAppHandle, message); } catch (RemoteException e) { - Log.e(TAG, "Could not fetch send message :" + e.toString()); + Log.w(TAG, "Could not send message :" + e.toString()); } return retVal; @@ -247,7 +235,7 @@ public final class ContextHubManager { public int registerCallback(Callback callback, Handler handler) { synchronized(this) { if (mCallback != null) { - Log.e(TAG, "Max number of callbacks reached!"); + Log.w(TAG, "Max number of callbacks reached!"); return -1; } mCallback = callback; @@ -268,7 +256,7 @@ public final class ContextHubManager { public int unregisterCallback(Callback callback) { synchronized(this) { if (callback != mCallback) { - Log.e(TAG, "Cannot recognize callback!"); + Log.w(TAG, "Cannot recognize callback!"); return -1; } @@ -311,11 +299,11 @@ public final class ContextHubManager { try { getBinder().registerCallback(mClientCallback); } catch (RemoteException e) { - Log.e(TAG, "Could not register callback:" + e); + Log.w(TAG, "Could not register callback:" + e); } } else { - Log.d(TAG, "failed to getService"); + Log.w(TAG, "failed to getService"); } } diff --git a/core/java/android/hardware/location/ContextHubMessage.java b/core/java/android/hardware/location/ContextHubMessage.java index 954e97dc7fce7..bca2ae6d2e8fc 100644 --- a/core/java/android/hardware/location/ContextHubMessage.java +++ b/core/java/android/hardware/location/ContextHubMessage.java @@ -16,10 +16,10 @@ package android.hardware.location; - import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; import java.util.Arrays; @@ -32,6 +32,9 @@ public class ContextHubMessage { private int mVersion; private byte[]mData; + private static final String TAG = "ContextHubMessage"; + + /** * Get the message type * @@ -106,9 +109,11 @@ public class ContextHubMessage { private ContextHubMessage(Parcel in) { mType = in.readInt(); mVersion = in.readInt(); - byte[] byteBuffer = new byte[in.readInt()]; - in.readByteArray(byteBuffer); + int bufferLength = in.readInt(); + mData = new byte[bufferLength]; + in.readByteArray(mData); } + public void writeToParcel(Parcel out, int flags) { out.writeInt(mType); out.writeInt(mVersion); diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java index 274babe6a9304..b65e24e3b81e0 100644 --- a/core/java/android/hardware/location/ContextHubService.java +++ b/core/java/android/hardware/location/ContextHubService.java @@ -29,12 +29,30 @@ import java.util.HashMap; */ public class ContextHubService extends IContextHubService.Stub { + public static final String CONTEXTHUB_SERVICE = "contexthub_service"; + 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 String CONTEXTHUB_SERVICE = "contexthub_service"; + + public static final int ANY_HUB = -1; + public static final int MSG_LOAD_NANO_APP = 5; + public static final int MSG_UNLOAD_NANO_APP = 2; + + 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 MSG_FIELD_TYPE = 0; + private static final int MSG_FIELD_VERSION = 1; + private static final int MSG_FIELD_HUB_HANDLE = 2; + private static final int MSG_FIELD_APP_INSTANCE = 3; + + private static final int OS_APP_INSTANCE = -1; private final Context mContext; @@ -42,44 +60,27 @@ public class ContextHubService extends IContextHubService.Stub { private ContextHubInfo[] mContextHubInfo; private IContextHubCallback mCallback; + private native int nativeSendMessage(int[] header, byte[] data); + private native ContextHubInfo[] nativeInitialize(); + + public ContextHubService(Context context) { mContext = context; mContextHubInfo = nativeInitialize(); + mNanoAppHash = new HashMap(); for (int i = 0; i < mContextHubInfo.length; i++) { - Log.v(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId() + Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId() + ", name: " + mContextHubInfo[i].getName()); } } - private native int nativeSendMessage(int[] header, byte[] data); - private native ContextHubInfo[] nativeInitialize(); - @Override - public int registerCallback(IContextHubCallback callback) throws RemoteException{ + public int registerCallback(IContextHubCallback callback) throws RemoteException { checkPermissions(); - mCallback = callback; - return 0; - } - - - private int onMessageReceipt(int[] header, byte[] data) { - if (mCallback != null) { - // TODO : Defend against unexpected header sizes - // Add abstraction for magic numbers - // onMessageRecipt should pass the right arguments - ContextHubMessage msg = new ContextHubMessage(header[0], header[1], data); - - try { - mCallback.onMessageReceipt(0, 0, msg); - } catch (Exception e) { - Log.e(TAG, "Exception " + e + " when calling remote callback"); - return -1; - } - } else { - Log.d(TAG, "Message Callback is NULL"); + synchronized(this) { + mCallback = callback; } - return 0; } @@ -118,14 +119,17 @@ public class ContextHubService extends IContextHubService.Stub { } // Call Native interface here - int[] msgHeader = new int[8]; - msgHeader[0] = contextHubHandle; - msgHeader[1] = app.getAppId(); - msgHeader[2] = app.getAppVersion(); - msgHeader[3] = ContextHubManager.MSG_LOAD_NANO_APP; - msgHeader[4] = 0; // Loading hints + int[] msgHeader = new int[MSG_HEADER_SIZE]; + msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle; + msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE; + msgHeader[MSG_FIELD_VERSION] = 0; + msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP; - return nativeSendMessage(msgHeader, app.getAppBinary()); + if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) { + return -1; + } + // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app + return 0; } @Override @@ -137,12 +141,18 @@ public class ContextHubService extends IContextHubService.Stub { } // Call Native interface here - int[] msgHeader = new int[8]; - msgHeader[0] = info.getContexthubId(); - msgHeader[1] = ContextHubManager.MSG_UNLOAD_NANO_APP; - msgHeader[2] = info.getHandle(); + int[] msgHeader = new int[MSG_HEADER_SIZE]; + msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB; + msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE; + msgHeader[MSG_FIELD_VERSION] = 0; + msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP; - return nativeSendMessage(msgHeader, null); + if(nativeSendMessage(msgHeader, null) != 0) { + return -1; + } + + // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app + return 0; } @Override @@ -166,7 +176,7 @@ public class ContextHubService extends IContextHubService.Stub { for(Integer nanoAppInstance : mNanoAppHash.keySet()) { NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance); - if(filter.testMatch(info)){ + if (filter.testMatch(info)){ foundInstances.add(nanoAppInstance); } } @@ -183,12 +193,12 @@ public class ContextHubService extends IContextHubService.Stub { public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException { checkPermissions(); - int[] msgHeader = new int[8]; - msgHeader[0] = ContextHubManager.MSG_DATA_SEND; - msgHeader[1] = hubHandle; - msgHeader[2] = nanoAppHandle; - msgHeader[3] = msg.getMsgType(); - msgHeader[4] = msg.getVersion(); + + int[] msgHeader = new int[MSG_HEADER_SIZE]; + msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle; + msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle; + msgHeader[MSG_FIELD_VERSION] = msg.getVersion(); + msgHeader[MSG_FIELD_TYPE] = msg.getMsgType(); return nativeSendMessage(msgHeader, msg.getData()); } @@ -196,5 +206,52 @@ public class ContextHubService extends IContextHubService.Stub { private void checkPermissions() { 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; + } + + synchronized(this) { + if (mCallback != null) { + ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE], + header[MSG_FIELD_VERSION], + data); + + try { + mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE], + header[MSG_FIELD_APP_INSTANCE], + msg); + } catch (Exception e) { + Log.w(TAG, "Exception " + e + " when calling remote callback"); + return -1; + } + } else { + Log.d(TAG, "Message Callback is NULL"); + } + } + + return 0; + } + + private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) { + // App Id encodes vendor & version + NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo(); + + appInfo.setAppId(appId); + appInfo.setAppVersion(appVersion); + appInfo.setName(PRE_LOADED_APP_NAME); + appInfo.setContexthubId(hubHandle); + appInfo.setHandle(appInstanceHandle); + appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER); + appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ); + appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ); + appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ); + + mNanoAppHash.put(appInstanceHandle, appInfo); + Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId + + " version " + appVersion); + + return 0; + } +} diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java index 369f9e44e8d94..8db70e9c53f1c 100644 --- a/core/java/android/hardware/location/NanoAppFilter.java +++ b/core/java/android/hardware/location/NanoAppFilter.java @@ -20,6 +20,7 @@ package android.hardware.location; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import android.util.Log; /** * @hide @@ -27,6 +28,8 @@ import android.os.Parcelable; @SystemApi public class NanoAppFilter { + private static final String TAG = "NanoAppFilter"; + // The appId, can be set to APP_ID_ANY private long mAppId; @@ -54,6 +57,10 @@ public class NanoAppFilter { * If this flag is set, only versions strictly less than the version specified shall match. */ public static final int FLAGS_VERSION_LESS_THAN = 4; + /** + * If this flag is set, only versions strictly equal to the + * version specified shall match. + */ public static final int FLAGS_VERSION_STRICTLY_EQUAL = 8; /** @@ -117,14 +124,9 @@ public class NanoAppFilter { * @return true if this is a match, false otherwise */ public boolean testMatch(NanoAppInstanceInfo info) { - if ((mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) && + return (mContextHubId == HUB_ANY || info.getContexthubId() == mContextHubId) && (mAppId == APP_ANY || info.getAppId() == mAppId) && - // (mAppIdVendorMask == VENDOR_ANY) TODO : Expose Vendor mask cleanly - (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()))) { - return true; - } else { - return false; - } + (versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion())); } public static final Parcelable.Creator CREATOR diff --git a/core/java/android/hardware/location/NanoAppInstanceInfo.java b/core/java/android/hardware/location/NanoAppInstanceInfo.java index ac62919b79317..977f645db199c 100644 --- a/core/java/android/hardware/location/NanoAppInstanceInfo.java +++ b/core/java/android/hardware/location/NanoAppInstanceInfo.java @@ -29,7 +29,7 @@ public class NanoAppInstanceInfo { private String mPublisher; private String mName; - private int mAppId; + private long mAppId; private int mAppVersion; private int mNeededReadMemBytes; @@ -59,6 +59,8 @@ public class NanoAppInstanceInfo { * set the publisher name for the app * * @param publisher - name of the publisher + * + * @hide */ public void setPublisher(String publisher) { mPublisher = publisher; @@ -77,6 +79,8 @@ public class NanoAppInstanceInfo { * set the name of the app * * @param name - name of the app + * + * @hide */ public void setName(String name) { mName = name; @@ -87,7 +91,7 @@ public class NanoAppInstanceInfo { * * @return int - application identifier */ - public int getAppId() { + public long getAppId() { return mAppId; } @@ -95,8 +99,10 @@ public class NanoAppInstanceInfo { * Set the application identifier * * @param appId - application identifier + * + * @hide */ - public void setAppId(int appId) { + public void setAppId(long appId) { mAppId = appId; } @@ -113,6 +119,8 @@ public class NanoAppInstanceInfo { * Set the application version * * @param appVersion - version of the app + * + * @hide */ public void setAppVersion(int appVersion) { mAppVersion = appVersion; @@ -131,6 +139,8 @@ public class NanoAppInstanceInfo { * Set the read memory needed by the app * * @param neededReadMemBytes - readable Memory needed in bytes + * + * @hide */ public void setNeededReadMemBytes(int neededReadMemBytes) { mNeededReadMemBytes = neededReadMemBytes; @@ -150,6 +160,8 @@ public class NanoAppInstanceInfo { * * @param neededWriteMemBytes - writable memory needed by the * app + * + * @hide */ public void setNeededWriteMemBytes(int neededWriteMemBytes) { mNeededWriteMemBytes = neededWriteMemBytes; @@ -169,6 +181,8 @@ public class NanoAppInstanceInfo { * * @param neededExecMemBytes - executable memory needed by the * app + * + * @hide */ public void setNeededExecMemBytes(int neededExecMemBytes) { mNeededExecMemBytes = neededExecMemBytes; @@ -187,6 +201,8 @@ public class NanoAppInstanceInfo { * set the sensors needed by this app * * @param neededSensors - all the sensors needed by this app + * + * @hide */ public void setNeededSensors(int[] neededSensors) { mNeededSensors = neededSensors; @@ -206,6 +222,8 @@ public class NanoAppInstanceInfo { * * @param outputEvents - the events that may be generated by * this app + * + * @hide */ public void setOutputEvents(int[] outputEvents) { mOutputEvents = outputEvents; @@ -224,6 +242,8 @@ public class NanoAppInstanceInfo { * set the context hub identifier * * @param contexthubId - system wide unique identifier + * + * @hide */ public void setContexthubId(int contexthubId) { mContexthubId = contexthubId; @@ -242,6 +262,8 @@ public class NanoAppInstanceInfo { * set the handle for an app instance * * @param handle - handle to this instance + * + * @hide */ public void setHandle(int handle) { mHandle = handle; @@ -252,7 +274,7 @@ public class NanoAppInstanceInfo { mPublisher = in.readString(); mName = in.readString(); - mAppId = in.readInt(); + mAppId = in.readLong(); mAppVersion = in.readInt(); mNeededReadMemBytes = in.readInt(); mNeededWriteMemBytes = in.readInt(); @@ -274,7 +296,7 @@ public class NanoAppInstanceInfo { public void writeToParcel(Parcel out, int flags) { out.writeString(mPublisher); out.writeString(mName); - out.writeInt(mAppId); + out.writeLong(mAppId); out.writeInt(mAppVersion); out.writeInt(mContexthubId); out.writeInt(mNeededReadMemBytes); @@ -286,7 +308,6 @@ public class NanoAppInstanceInfo { out.writeInt(mOutputEvents.length); out.writeIntArray(mOutputEvents); - } public static final Parcelable.Creator CREATOR diff --git a/core/jni/android_hardware_location_ContextHubService.cpp b/core/jni/android_hardware_location_ContextHubService.cpp index 87247292a73b8..42dc983792d20 100644 --- a/core/jni/android_hardware_location_ContextHubService.cpp +++ b/core/jni/android_hardware_location_ContextHubService.cpp @@ -16,23 +16,39 @@ #include "context_hub.h" +#define LOG_NDEBUG 0 +#define LOG_TAG "ContextHubService" + +#include +#include +#include +#include #include #include #include +#include + +#include -#include #include "JNIHelp.h" #include "core_jni_helpers.h" -#include "stdint.h" -#include "stdlib.h" + +//static constexpr int OS_APP_ID=-1; + +static constexpr int MIN_APP_ID=1; +static constexpr int MAX_APP_ID=128; + +static constexpr size_t MSG_HEADER_SIZE=4; +static constexpr int HEADER_FIELD_MSG_TYPE=0; +//static constexpr int HEADER_FIELD_MSG_VERSION=1; +static constexpr int HEADER_FIELD_HUB_HANDLE=2; +static constexpr int HEADER_FIELD_APP_INSTANCE=3; namespace android { namespace { -// TODO: We should share this array_length function widely around Android -// code. /* * Finds the length of a statically-sized array using template trickery that * also prevents it from being applied to the wrong type. @@ -64,35 +80,207 @@ struct jniInfo_s { jmethodID contextHubInfoSetPeakPowerDrawMw; jmethodID contextHubInfoSetSupportedSensors; jmethodID contextHubInfoSetMemoryRegions; + jmethodID contextHubInfoSetMaxPacketLenBytes; jmethodID contextHubServiceMsgReceiptCallback; + jmethodID contextHubServiceAddAppInstance; }; struct context_hub_info_s { - int cookie; + uint32_t *cookies; int numHubs; const struct context_hub_t *hubs; struct context_hub_module_t *contextHubModule; }; +struct app_instance_info_s { + uint32_t hubHandle; // Id of the hub this app is on + int instanceId; // systemwide unique instance id - assigned + struct hub_app_info appInfo; // returned from the HAL + uint64_t truncName; // Possibly truncated name - logging +}; + struct contextHubServiceDb_s { int initialized; context_hub_info_s hubInfo; jniInfo_s jniInfo; + std::queue freeIds; + std::map appInstances; }; } // unnamed namespace static contextHubServiceDb_s db; -int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg, +int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg, void *cookie); +const context_hub_t *get_hub_info(int hubHandle) { + if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) { + return &db.hubInfo.hubs[hubHandle]; + } + return nullptr; +} + +static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) { + const context_hub_t *info = get_hub_info(hubHandle); + + if (info) { + return db.hubInfo.contextHubModule->send_message(info->hub_id, msg); + } else { + ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle); + return -1; + } +} + +static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) { + const context_hub_t *info = get_hub_info(hubHandle); + + if (info) { + msg->app = info->os_app_name; + return 0; + } else { + ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle); + return -1; + } +} + +static int get_hub_id_for_app_instance(int id) { + if (db.appInstances.find(id) == db.appInstances.end()) { + ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id); + return -1; + } + + int hubHandle = db.appInstances[id]->hubHandle; + + return db.hubInfo.hubs[hubHandle].hub_id; +} + +static int set_dest_app(hub_message_t *msg, int id) { + if (db.appInstances.find(id) == db.appInstances.end()) { + ALOGD("%s: Cannod find app for app instance %d", __FUNCTION__, id); + return -1; + } + + msg->app = db.appInstances[id]->appInfo.name; + return 0; +} + +static void send_query_for_apps() { + hub_message_t msg; + + msg.message_type = CONTEXT_HUB_QUERY_APPS; + msg.message_len = 0; + + for (int i = 0; i < db.hubInfo.numHubs; i++ ) { + ALOGD("Sending query for apps to hub %d", i); + set_os_app_as_destination(&msg, i); + if (send_msg_to_hub(&msg, i) != 0) { + ALOGW("Could not query hub %i for apps", i); + } + } +} + +static int return_id(int id) { + // Note : This method is not thread safe. + // id returned is guarenteed to be in use + db.freeIds.push(id); + return 0; +} + +static int generate_id(void) { + // Note : This method is not thread safe. + int retVal = -1; + + if (!db.freeIds.empty()) { + retVal = db.freeIds.front(); + db.freeIds.pop(); + } + + return retVal; +} + +int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle, JNIEnv *env) { + // Not checking if the apps are indeed distinct + + app_instance_info_s *entry; + void *appName; + hub_app_name_t *name; + + assert(appInfo && appInfo->name && appInfo->name->app_name); + + entry = (app_instance_info_s *) malloc(sizeof(app_instance_info_s)); + appName = malloc(appInfo->name->app_name_len); + name = (hub_app_name_t *) malloc(sizeof(hub_app_name_t)); + + int appInstanceHandle = generate_id(); + + if (appInstanceHandle < 0 || !appName || !entry || !name) { + ALOGE("Cannot find resources to add app instance %d, %p, %p", + appInstanceHandle, appName, entry); + + free(appName); + free(entry); + free(name); + + if (appInstanceHandle >= 0) { + return_id(appInstanceHandle); + } + + return -1; + } + + memcpy(&(entry->appInfo), appInfo, sizeof(entry->appInfo)); + memcpy(appName, appInfo->name->app_name, appInfo->name->app_name_len); + name->app_name = appName; + name->app_name_len = appInfo->name->app_name_len; + entry->appInfo.name = name; + entry->truncName = 0; + memcpy(&(entry->truncName), name->app_name, + sizeof(entry->truncName) < name->app_name_len ? + sizeof(entry->truncName) : name->app_name_len); + + // Not checking for sanity of hubId + entry->hubHandle = hubHandle; + entry->instanceId = appInstanceHandle; + db.appInstances[appInstanceHandle] = entry; + + // Finally - let the service know of this app instance + env->CallIntMethod(db.jniInfo.jContextHubService, + db.jniInfo.contextHubServiceAddAppInstance, + hubHandle, entry->instanceId, entry->truncName, + entry->appInfo.version); + + ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32 + " as appInstance %d, original name_length %" PRId32, entry->truncName, + entry->hubHandle, appInstanceHandle, name->app_name_len); + + return appInstanceHandle; +} + +int delete_app_instance(int id) { + if (db.appInstances.find(id) == db.appInstances.end()) { + return -1; + } + + return_id(id); + + if (db.appInstances[id]) { + // Losing the const cast below. This is intentional. + free((void *)db.appInstances[id]->appInfo.name->app_name); + free((void *)db.appInstances[id]->appInfo.name); + free(db.appInstances[id]); + db.appInstances.erase(id); + } + + return 0; +} + + static void initContextHubService() { int err = 0; - db.hubInfo.hubs = NULL; + db.hubInfo.hubs = nullptr; db.hubInfo.numHubs = 0; - db.hubInfo.cookie = 0; int i; err = hw_get_module(CONTEXT_HUB_MODULE_ID, @@ -103,26 +291,45 @@ static void initContextHubService() { strerror(-err)); } - if (db.hubInfo.contextHubModule) { - ALOGD("Fetching hub info"); - db.hubInfo.numHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule, - &db.hubInfo.hubs); + // Prep for storing app info + for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) { + db.freeIds.push(i); + } - if (db.hubInfo.numHubs > 0) { - for (i = 0; i < db.hubInfo.numHubs; i++) { - // TODO : Event though one cookie is OK for now, lets change - // this to be one per hub - db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id, - context_hub_callback, - &db.hubInfo.cookie); + if (db.hubInfo.contextHubModule) { + int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule, + &db.hubInfo.hubs); + ALOGD("ContextHubModule returned %d hubs ", retNumHubs); + db.hubInfo.numHubs = retNumHubs; + + if (db.hubInfo.numHubs > 0) { + db.hubInfo.numHubs = retNumHubs; + db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs); + + if (!db.hubInfo.cookies) { + ALOGW("Ran out of memory allocating cookies, bailing"); + return; + } + + for (i = 0; i < db.hubInfo.numHubs; i++) { + db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id; + if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id, + context_hub_callback, + &db.hubInfo.cookies[i]) == 0) { + } + } } - } + + send_query_for_apps(); + } else { + ALOGW("No Context Hub Module present"); } } static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) { JNIEnv *env; - if ((db.jniInfo.vm)->AttachCurrentThread(&env, NULL) != JNI_OK) { + + if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) { return -1; } @@ -132,28 +339,131 @@ static int onMessageReceipt(int *header, int headerLen, char *msg, int msgLen) { env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg); env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header); - - return env->CallIntMethod(db.jniInfo.jContextHubService, + return (env->CallIntMethod(db.jniInfo.jContextHubService, db.jniInfo.contextHubServiceMsgReceiptCallback, - jheader, jmsg); + jheader, jmsg) != 0); } -int context_hub_callback(uint32_t hub_id, const struct hub_message_t *msg, +int handle_query_apps_response(char *msg, int msgLen, uint32_t hubHandle) { + int i; + JNIEnv *env; + if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) { + return -1; + } + + int numApps = msgLen/sizeof(hub_app_info); + hub_app_info *info = (hub_app_info *)malloc(msgLen); // handle possible alignment + + if (!info) { + return -1; + } + + memcpy(info, msg, msgLen); + for (i = 0; i < numApps; i++) { + add_app_instance(info, hubHandle, env); + info++; + } + + free(info); + + return 0; +} + + +int handle_os_message(uint32_t msgType, uint32_t hubHandle, + char *msg, int msgLen) { + int retVal; + + switch(msgType) { + case CONTEXT_HUB_APPS_ENABLE: + retVal = 0; + break; + + case CONTEXT_HUB_APPS_DISABLE: + retVal = 0; + break; + + case CONTEXT_HUB_LOAD_APP: + retVal = 0; + break; + + case CONTEXT_HUB_UNLOAD_APP: + retVal = 0; + break; + + case CONTEXT_HUB_QUERY_APPS: + retVal = handle_query_apps_response(msg, msgLen, hubHandle); + break; + + case CONTEXT_HUB_QUERY_MEMORY: + retVal = 0; + break; + + case CONTEXT_HUB_LOAD_OS: + retVal = 0; + break; + + default: + retVal = -1; + break; + + } + + return retVal; +} + +static bool sanity_check_cookie(void *cookie, uint32_t hub_id) { + int *ptr = (int *)cookie; + + if (!ptr || *ptr >= db.hubInfo.numHubs) { + return false; + } + + if (db.hubInfo.hubs[*ptr].hub_id != hub_id) { + return false; + } else { + return true; + } +} + +int context_hub_callback(uint32_t hubId, + const struct hub_message_t *msg, void *cookie) { - int msgHeader[4]; + int msgHeader[MSG_HEADER_SIZE]; - msgHeader[0] = msg->message_type; - msgHeader[1] = 0; // TODO : HAL does not have a version field - msgHeader[2] = hub_id; + if (!msg) { + return -1; + } - onMessageReceipt(msgHeader, sizeof(msgHeader), (char *)msg->message, msg->message_len); // TODO : Populate this - return 0; + msgHeader[HEADER_FIELD_MSG_TYPE] = msg->message_type; + + if (!sanity_check_cookie(cookie, hubId)) { + ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing", + hubId, cookie); + + return -1; + } + + msgHeader[HEADER_FIELD_HUB_HANDLE] = *(uint32_t*)cookie; + + if (msgHeader[HEADER_FIELD_MSG_TYPE] < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE && + msgHeader[HEADER_FIELD_MSG_TYPE] != 0 ) { + handle_os_message(msgHeader[HEADER_FIELD_MSG_TYPE], + msgHeader[HEADER_FIELD_HUB_HANDLE], + (char *)msg->message, + msg->message_len); + } else { + onMessageReceipt(msgHeader, sizeof(msgHeader), + (char *)msg->message, msg->message_len); + } + + return 0; } static int init_jni(JNIEnv *env, jobject instance) { if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) { - return -1; + return -1; } db.jniInfo.jContextHubService = env->NewGlobalRef(instance); @@ -167,7 +477,6 @@ static int init_jni(JNIEnv *env, jobject instance) { db.jniInfo.memoryRegionsClass = env->FindClass("android/hardware/location/MemoryRegion"); - //TODO :: Add error checking db.jniInfo.contextHubInfoCtor = env->GetMethodID(db.jniInfo.contextHubInfoClass, "", "()V"); db.jniInfo.contextHubInfoSetId = @@ -209,6 +518,9 @@ static int init_jni(JNIEnv *env, jobject instance) { 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 = @@ -218,6 +530,11 @@ static int init_jni(JNIEnv *env, jobject instance) { env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName", "(Ljava/lang/String;)V"); + db.jniInfo.contextHubServiceAddAppInstance = + env->GetMethodID(db.jniInfo.contextHubServiceClass, + "addAppInstance", "(IIJI)I"); + + return 0; } @@ -245,20 +562,29 @@ static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version); env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version); env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips); - env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw, hub->stopped_power_draw_mw); - env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw, hub->sleep_power_draw_mw); - env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw, hub->peak_power_draw_mw); + env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw, + hub->stopped_power_draw_mw); + env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw, + hub->sleep_power_draw_mw); + env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw, + hub->peak_power_draw_mw); + env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes, + hub->max_supported_msg_len); + // TODO : jintBuf = env->NewIntArray(hub->num_connected_sensors); - // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, hub->connected_sensors); + // TODO : env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, + // hub->connected_sensors); jintBuf = env->NewIntArray(array_length(dummyConnectedSensors)); env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors, dummyConnectedSensors); + env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, 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, NULL); + 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); + return jHub; } @@ -267,18 +593,18 @@ static jobjectArray nativeInitialize(JNIEnv *env, jobject instance) jobject hub; jobjectArray retArray; - initContextHubService(); - if (init_jni(env, instance) < 0) { - return NULL; + return nullptr; } - // Note : The service is clamping the number of hubs to 1 - db.hubInfo.numHubs = 1; - initContextHubService(); - retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, NULL); + 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]); @@ -291,28 +617,27 @@ static jobjectArray nativeInitialize(JNIEnv *env, jobject instance) static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_, jbyteArray data_) { hub_message_t msg; - hub_app_name_t dest; - uint8_t os_name[8]; - - memset(os_name, 0, sizeof(os_name)); + jint retVal = -1; // Default to failure jint *header = env->GetIntArrayElements(header_, 0); - //int numHeaderElements = env->GetArrayLength(header_); + unsigned int numHeaderElements = env->GetArrayLength(header_); jbyte *data = env->GetByteArrayElements(data_, 0); int dataBufferLength = env->GetArrayLength(data_); - /* Assume an int - thats all we understand */ - dest.app_name_len = array_length(os_name); // TODO : Check this - //dest.app_name = &header[1]; - dest.app_name = os_name; - - msg.app = &dest; - - msg.message_type = header[3]; - msg.message_len = dataBufferLength; - msg.message = data; - - jint retVal = db.hubInfo.contextHubModule->send_message(header[0], &msg); + if (numHeaderElements >= MSG_HEADER_SIZE) { + if (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0) { + msg.message_type = header[HEADER_FIELD_MSG_TYPE]; + msg.message_len = dataBufferLength; + msg.message = data; + retVal = db.hubInfo.contextHubModule->send_message( + get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]), + &msg); + } else { + ALOGD("Could not find app instance %d", header[HEADER_FIELD_APP_INSTANCE]); + } + } else { + ALOGD("Malformed header len"); + } env->ReleaseIntArrayElements(header_, header, 0); env->ReleaseByteArrayElements(data_, data, 0);