OSDN Git Service

Added handling apps query response from context hub
authorAshutosh Joshi <ashutoshj@google.com>
Tue, 29 Mar 2016 16:19:56 +0000 (09:19 -0700)
committerPeng Xu <pengxu@google.com>
Sat, 2 Apr 2016 03:10:27 +0000 (20:10 -0700)
Added handling of app query reponse from context hub.
Exposed the maximum message size to clients.

Change-Id: Ie96a860774d005ad6ad72acc88dc79964835486b

api/system-current.txt
core/java/android/hardware/location/ContextHubInfo.java
core/java/android/hardware/location/ContextHubManager.java
core/java/android/hardware/location/ContextHubMessage.java
core/java/android/hardware/location/ContextHubService.java
core/java/android/hardware/location/NanoAppFilter.java
core/java/android/hardware/location/NanoAppInstanceInfo.java
core/jni/android_hardware_location_ContextHubService.cpp

index e1e73e9..fe562bb 100644 (file)
@@ -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<android.hardware.location.NanoAppInstanceInfo> CREATOR;
   }
index 644e29f..ae44f1d 100644 (file)
@@ -37,6 +37,7 @@ public class ContextHubInfo {
     private float mStoppedPowerDrawMw;
     private float mSleepPowerDrawMw;
     private float mPeakPowerDrawMw;
+    private int mMaxPacketLengthBytes;
 
     private int[] mSupportedSensors;
 
@@ -46,6 +47,27 @@ public class 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
      *
      * @return int - unique system wide identifier
@@ -374,4 +396,4 @@ public class ContextHubInfo {
             return new ContextHubInfo[size];
         }
     };
-}
+}
\ No newline at end of file
index 4ddf767..89edaa9 100644 (file)
@@ -43,23 +43,6 @@ public final class ContextHubManager {
     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.
      */
     public abstract static class Callback {
@@ -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");
         }
     }
 
index 954e97d..bca2ae6 100644 (file)
 
 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);
index 274babe..b65e24e 100644 (file)
@@ -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<Integer, NanoAppInstanceInfo>();
 
         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
-
-        return nativeSendMessage(msgHeader, app.getAppBinary());
+        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;
+
+        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;
+
+        if(nativeSendMessage(msgHeader, null) != 0) {
+            return -1;
+        }
 
-        return nativeSendMessage(msgHeader, null);
+        // 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;
+    }
+}
index 369f9e4..8db70e9 100644 (file)
@@ -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<NanoAppFilter> CREATOR
index ac62919..977f645 100644 (file)
@@ -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<NanoAppInstanceInfo> CREATOR
index 8724729..42dc983 100644 (file)
 
 #include "context_hub.h"
 
+#define LOG_NDEBUG 0
+#define LOG_TAG "ContextHubService"
+
+#include <inttypes.h>
+#include <jni.h>
+#include <map>
+#include <queue>
 #include <string.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <stdlib.h>
+
+#include <cutils/log.h>
 
-#include <jni.h>
 #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<int> freeIds;
+    std::map<int, app_instance_info_s *> 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));
     }
 
+    // Prep for storing app info
+    for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
+        db.freeIds.push(i);
+    }
+
     if (db.hubInfo.contextHubModule) {
-      ALOGD("Fetching hub info");
-      db.hubInfo.numHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
+        int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
                                                                  &db.hubInfo.hubs);
-
-      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);
+        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 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 hub_id, const struct hub_message_t *msg,
+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;
+    }
+
+    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);
+    }
 
-  onMessageReceipt(msgHeader, sizeof(msgHeader), (char *)msg->message, msg->message_len); // TODO : Populate this
-  return 0;
+    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, "<init>", "()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);