Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2016, The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #undef LOG_NDEBUG
     18 #undef LOG_TAG
     19 #define LOG_NDEBUG 0
     20 #define LOG_TAG "ContextHubService"
     21 
     22 #include <inttypes.h>
     23 #include <jni.h>
     24 #include <stdint.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <string.h>
     28 #include <sys/endian.h>
     29 
     30 #include <chrono>
     31 #include <mutex>
     32 #include <queue>
     33 #include <unordered_map>
     34 #include <utility>
     35 
     36 #include <android-base/macros.h>
     37 #include <android/hardware/contexthub/1.0/IContexthub.h>
     38 #include <cutils/log.h>
     39 
     40 #include "core_jni_helpers.h"
     41 #include "JNIHelp.h"
     42 
     43 using android::hardware::contexthub::V1_0::AsyncEventType;
     44 using android::hardware::contexthub::V1_0::ContextHub;
     45 using android::hardware::contexthub::V1_0::ContextHubMsg;
     46 using android::hardware::contexthub::V1_0::HubAppInfo;
     47 using android::hardware::contexthub::V1_0::IContexthub;
     48 using android::hardware::contexthub::V1_0::IContexthubCallback;
     49 using android::hardware::contexthub::V1_0::NanoAppBinary;
     50 using android::hardware::contexthub::V1_0::Result;
     51 using android::hardware::contexthub::V1_0::TransactionResult;
     52 
     53 using android::hardware::Return;
     54 
     55 using std::chrono::steady_clock;
     56 
     57 // If a transaction takes longer than this, we'll allow it to be
     58 // canceled by a new transaction.  Note we do _not_ automatically
     59 // cancel a transaction after this much time.  We can have a
     60 // legal transaction which takes longer than this amount of time,
     61 // as long as no other new transactions are attempted after this
     62 // time has expired.
     63 constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
     64 
     65 namespace android {
     66 
     67 constexpr uint32_t kNanoAppBinaryHeaderVersion = 1;
     68 
     69 // Important: this header is explicitly defined as little endian byte order, and
     70 // therefore may not match host endianness
     71 struct NanoAppBinaryHeader {
     72     uint32_t headerVersion;        // 0x1 for this version
     73     uint32_t magic;                // "NANO" (see NANOAPP_MAGIC in context_hub.h)
     74     uint64_t appId;                // App Id, contains vendor id
     75     uint32_t appVersion;           // Version of the app
     76     uint32_t flags;                // Signed, encrypted
     77     uint64_t hwHubType;            // Which hub type is this compiled for
     78     uint8_t targetChreApiMajorVersion; // Which CHRE API version this is compiled for
     79     uint8_t targetChreApiMinorVersion;
     80     uint8_t reserved[6];
     81 } __attribute__((packed));
     82 
     83 enum HubMessageType {
     84     CONTEXT_HUB_APPS_ENABLE  = 1, // Enables loaded nano-app(s)
     85     CONTEXT_HUB_APPS_DISABLE = 2, // Disables loaded nano-app(s)
     86     CONTEXT_HUB_LOAD_APP     = 3, // Load a supplied app
     87     CONTEXT_HUB_UNLOAD_APP   = 4, // Unload a specified app
     88     CONTEXT_HUB_QUERY_APPS   = 5, // Query for app(s) info on hub
     89     CONTEXT_HUB_QUERY_MEMORY = 6, // Query for memory info
     90     CONTEXT_HUB_OS_REBOOT    = 7, // Request to reboot context HUB OS
     91 };
     92 
     93 constexpr jint OS_APP_ID = -1;
     94 constexpr jint INVALID_APP_ID = -2;
     95 
     96 constexpr jint MIN_APP_ID = 1;
     97 constexpr jint MAX_APP_ID = 128;
     98 
     99 constexpr size_t MSG_HEADER_SIZE = 4;
    100 constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
    101 constexpr size_t HEADER_FIELD_MSG_VERSION = 1;
    102 constexpr size_t HEADER_FIELD_HUB_HANDLE = 2;
    103 constexpr size_t HEADER_FIELD_APP_INSTANCE = 3;
    104 
    105 constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
    106 constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
    107 constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
    108 
    109 jint getAppInstanceForAppId(uint64_t app_id);
    110 int onMessageReceipt(const uint32_t *header,
    111                      size_t headerLen,
    112                      const char *msg,
    113                      size_t msgLen);
    114 void onHubReset(uint32_t hubId);
    115 void queryHubForApps(uint32_t hubId);
    116 void passOnOsResponse(uint32_t hubHandle,
    117                       uint32_t msgType,
    118                       TransactionResult result,
    119                       const int8_t *additionalData,
    120                       size_t additionalDataLen);
    121 
    122 bool closeLoadTxn(bool success, jint *appInstanceHandle);
    123 void closeUnloadTxn(bool success);
    124 int handleQueryAppsResponse(const std::vector<HubAppInfo> apps,
    125                                uint32_t hubHandle);
    126 
    127 struct JniInfo {
    128     JavaVM *vm;
    129     jclass contextHubInfoClass;
    130     jclass contextHubServiceClass;
    131     jclass memoryRegionsClass;
    132 
    133     jobject jContextHubService;
    134 
    135     jmethodID msgReceiptCallBack;
    136 
    137     jmethodID contextHubInfoCtor;
    138     jmethodID contextHubInfoSetId;
    139     jmethodID contextHubInfoSetName;
    140     jmethodID contextHubInfoSetVendor;
    141     jmethodID contextHubInfoSetToolchain;
    142     jmethodID contextHubInfoSetPlatformVersion;
    143     jmethodID contextHubInfoSetStaticSwVersion;
    144     jmethodID contextHubInfoSetToolchainVersion;
    145     jmethodID contextHubInfoSetPeakMips;
    146     jmethodID contextHubInfoSetStoppedPowerDrawMw;
    147     jmethodID contextHubInfoSetSleepPowerDrawMw;
    148     jmethodID contextHubInfoSetPeakPowerDrawMw;
    149     jmethodID contextHubInfoSetSupportedSensors;
    150     jmethodID contextHubInfoSetMemoryRegions;
    151     jmethodID contextHubInfoSetMaxPacketLenBytes;
    152 
    153     jmethodID contextHubServiceMsgReceiptCallback;
    154     jmethodID contextHubServiceAddAppInstance;
    155     jmethodID contextHubServiceDeleteAppInstance;
    156 };
    157 
    158 
    159 
    160 class TxnManager {
    161 public:
    162     TxnManager() {
    163         mData = nullptr;
    164         mIsPending = false;
    165     }
    166 
    167     ~TxnManager() {
    168         closeTxn();
    169     }
    170 
    171     int addTxn(HubMessageType txnIdentifier, void *txnData) {
    172         std::lock_guard<std::mutex>lock(mLock);
    173         if (mIsPending) {
    174             ALOGW("Transaction already found pending when trying to add a new one.");
    175             return -1;
    176         }
    177         mIsPending = true;
    178         mFirstTimeTxnCanBeCanceled = steady_clock::now() + kMinTransactionCancelTime;
    179         mData = txnData;
    180         mIdentifier = txnIdentifier;
    181 
    182         return 0;
    183     }
    184 
    185     int closeTxn() {
    186         std::lock_guard<std::mutex>lock(mLock);
    187         closeTxnUnlocked();
    188         return 0;
    189     }
    190 
    191     bool isTxnPending() {
    192         std::lock_guard<std::mutex>lock(mLock);
    193         return mIsPending;
    194     }
    195 
    196     void closeAnyStaleTxns() {
    197         std::lock_guard<std::mutex>lock(mLock);
    198         if (mIsPending && steady_clock::now() >= mFirstTimeTxnCanBeCanceled) {
    199             ALOGW("Stale transaction canceled");
    200             closeTxnUnlocked();
    201         }
    202     }
    203 
    204     int fetchTxnData(HubMessageType *id, void **data) {
    205         if (id == nullptr || data == nullptr) {
    206             ALOGW("Null Params isNull{id, data} {%d, %d}",
    207                   id == nullptr ? 1 : 0,
    208                   data == nullptr ? 1 : 0);
    209             return -1;
    210         }
    211 
    212         std::lock_guard<std::mutex>lock(mLock);
    213         if (!mIsPending) {
    214             ALOGW("No Transactions pending");
    215             return -1;
    216         }
    217 
    218         *id = mIdentifier;
    219         *data = mData;
    220         return 0;
    221     }
    222 
    223  private:
    224     bool mIsPending;            // Is a transaction pending
    225     std::mutex mLock;           // mutex for manager
    226     HubMessageType mIdentifier; // What are we doing
    227     void *mData;                // Details
    228     steady_clock::time_point mFirstTimeTxnCanBeCanceled;
    229 
    230     // Only call this if you hold the lock.
    231     void closeTxnUnlocked() {
    232         mIsPending = false;
    233         free(mData);
    234         mData = nullptr;
    235     }
    236 };
    237 
    238 
    239 struct ContextHubServiceCallback : IContexthubCallback {
    240     uint32_t mContextHubId;
    241 
    242     ContextHubServiceCallback(uint32_t hubId) {
    243         mContextHubId = hubId;
    244     }
    245 
    246     virtual Return<void> handleClientMsg(const ContextHubMsg &msg) {
    247         jint appHandle = getAppInstanceForAppId(msg.appName);
    248         if (appHandle < 0) {
    249             ALOGE("Filtering out message due to invalid App Instance.");
    250         } else {
    251             uint32_t msgHeader[MSG_HEADER_SIZE] = {};
    252             msgHeader[HEADER_FIELD_MSG_TYPE] = msg.msgType;
    253             msgHeader[HEADER_FIELD_HUB_HANDLE] = mContextHubId;
    254             msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle;
    255             onMessageReceipt(msgHeader,
    256                              MSG_HEADER_SIZE,
    257                              reinterpret_cast<const char *>(msg.msg.data()),
    258                              msg.msg.size());
    259         }
    260 
    261         return android::hardware::Void();
    262     }
    263 
    264     virtual Return<void> handleHubEvent(AsyncEventType evt) {
    265         if (evt == AsyncEventType::RESTARTED) {
    266             ALOGW("Context Hub handle %d restarted", mContextHubId);
    267             onHubReset(mContextHubId);
    268         } else {
    269             ALOGW("Cannot handle event %u from hub %d", evt, mContextHubId);
    270         }
    271 
    272         return android::hardware::Void();
    273     }
    274 
    275     virtual Return<void> handleTxnResult(uint32_t txnId,
    276                                          TransactionResult result) {
    277         ALOGI("Handle transaction result , hubId %" PRIu32 ", txnId %" PRIu32 ", result %" PRIu32,
    278               mContextHubId,
    279               txnId,
    280               result);
    281 
    282         switch(txnId) {
    283             case CONTEXT_HUB_APPS_ENABLE:
    284             case CONTEXT_HUB_APPS_DISABLE:
    285                 passOnOsResponse(mContextHubId, txnId, result, nullptr, 0);
    286                 break;
    287 
    288             case CONTEXT_HUB_UNLOAD_APP:
    289                 closeUnloadTxn(result == TransactionResult::SUCCESS);
    290                 passOnOsResponse(mContextHubId, txnId, result, nullptr, 0);
    291                 break;
    292 
    293             case CONTEXT_HUB_LOAD_APP:
    294                 {
    295                     jint appInstanceHandle = INVALID_APP_ID;
    296                     bool appRunningOnHub = (result == TransactionResult::SUCCESS);
    297                     if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
    298                         if (appRunningOnHub) {
    299                             // Now we're in an odd situation.  Our nanoapp
    300                             // is up and running on the Context Hub.  However,
    301                             // something went wrong in our Service code so that
    302                             // we're not able to properly track this nanoapp
    303                             // in our Service code.  If we tell the Java layer
    304                             // things are good, it's a lie because the handle
    305                             // we give them will fail when used with the Service.
    306                             // If we tell the Java layer this failed, it's kind
    307                             // of a lie as well, since this nanoapp is running.
    308                             //
    309                             // We leave a more robust fix for later, and for
    310                             // now just tell the user things have failed.
    311                             //
    312                             // TODO(b/30835981): Make this situation better.
    313                             result = TransactionResult::FAILURE;
    314                         }
    315                     }
    316 
    317                     passOnOsResponse(mContextHubId,
    318                                      txnId,
    319                                      result,
    320                                      reinterpret_cast<int8_t *>(&appInstanceHandle),
    321                                      sizeof(appInstanceHandle));
    322                     break;
    323                 }
    324 
    325             default:
    326                 ALOGI("unrecognized transction id %" PRIu32, txnId);
    327                 break;
    328         }
    329         return android::hardware::Void();
    330     }
    331 
    332     virtual Return<void> handleAppsInfo(
    333             const android::hardware::hidl_vec<HubAppInfo>& apps) {
    334         TransactionResult result = TransactionResult::SUCCESS;
    335         handleQueryAppsResponse(apps,mContextHubId);
    336         passOnOsResponse(mContextHubId, CONTEXT_HUB_QUERY_APPS, result, nullptr, 0);
    337         return android::hardware::Void();
    338     }
    339 
    340     virtual Return<void> handleAppAbort(uint64_t appId, uint32_t abortCode) {
    341         ALOGI("Handle app aport called from %" PRIx64 " with abort code %" PRIu32,
    342             appId,
    343             abortCode);
    344 
    345         // TODO: Plumb this to the clients interested in this app
    346         return android::hardware::Void();
    347     }
    348 
    349     void setContextHubId(uint32_t id) {
    350         mContextHubId = id;
    351     }
    352 
    353     uint32_t getContextHubId() {
    354         return(mContextHubId);
    355     }
    356 };
    357 
    358 struct AppInstanceInfo {
    359     HubAppInfo appInfo;          // returned from the HAL
    360     uint64_t truncName;          // Possibly truncated name for logging
    361     uint32_t hubHandle;          // Id of the hub this app is on
    362     jint instanceId;             // system wide unique instance id - assigned
    363 };
    364 
    365 struct ContextHubInfo {
    366     int numHubs;
    367     Vector<ContextHub> hubs;
    368     sp<IContexthub> contextHub;
    369 };
    370 
    371 struct ContextHubServiceDb {
    372     int initialized;
    373     ContextHubInfo hubInfo;
    374     JniInfo jniInfo;
    375     std::queue<jint> freeIds;
    376     std::unordered_map<jint, AppInstanceInfo> appInstances;
    377     TxnManager txnManager;
    378     std::vector<ContextHubServiceCallback *> regCallBacks;
    379 };
    380 
    381 ContextHubServiceDb db;
    382 
    383 bool getHubIdForHubHandle(int hubHandle, uint32_t *hubId) {
    384     if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs || hubId == nullptr) {
    385         return false;
    386     } else {
    387         *hubId = db.hubInfo.hubs[hubHandle].hubId;
    388         return true;
    389     }
    390 }
    391 
    392 int getHubHandleForAppInstance(jint id) {
    393     if (!db.appInstances.count(id)) {
    394         ALOGD("%s: Cannot find app for app instance %" PRId32,
    395               __FUNCTION__,
    396               id);
    397         return -1;
    398     }
    399 
    400     return db.appInstances[id].hubHandle;
    401 }
    402 
    403 jint getAppInstanceForAppId(uint64_t app_id) {
    404     auto end = db.appInstances.end();
    405     for (auto current = db.appInstances.begin(); current != end; ++current) {
    406         if (current->second.appInfo.appId == app_id) {
    407             return current->first;
    408         }
    409     }
    410     ALOGD("Cannot find app for app id %" PRIu64 ".", app_id);
    411     return -1;
    412 }
    413 
    414 uint64_t getAppIdForAppInstance(jint id) {
    415     if (!db.appInstances.count(id)) {
    416         return INVALID_APP_ID;
    417     }
    418     return db.appInstances[id].appInfo.appId;
    419 }
    420 
    421 void queryHubForApps(uint32_t hubId) {
    422     Result r = db.hubInfo.contextHub->queryApps(hubId);
    423     ALOGD("Sent query for apps to hub %" PRIu32 " with result %" PRIu32, hubId, r);
    424 }
    425 
    426 void sendQueryForApps() {
    427     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
    428         queryHubForApps(db.hubInfo.hubs[i].hubId);
    429     }
    430 }
    431 
    432 int returnId(jint id) {
    433     // Note : This method is not thread safe.
    434     // id returned is guaranteed to be in use
    435     if (id >= 0) {
    436         db.freeIds.push(id);
    437         return 0;
    438     }
    439 
    440     return -1;
    441 }
    442 
    443 jint generateId() {
    444     // Note : This method is not thread safe.
    445     jint retVal = -1;
    446 
    447     if (!db.freeIds.empty()) {
    448         retVal = db.freeIds.front();
    449         db.freeIds.pop();
    450     }
    451 
    452     return retVal;
    453 }
    454 
    455 jint addAppInstance(const HubAppInfo *appInfo, uint32_t hubHandle,
    456         jint appInstanceHandle, JNIEnv *env) {
    457     // Not checking if the apps are indeed distinct
    458     AppInstanceInfo entry;
    459     assert(appInfo);
    460 
    461 
    462     entry.appInfo = *appInfo;
    463 
    464     entry.instanceId = appInstanceHandle;
    465     entry.truncName = appInfo->appId;
    466     entry.hubHandle = hubHandle;
    467     db.appInstances[appInstanceHandle] = entry;
    468     // Finally - let the service know of this app instance, to populate
    469     // the Java cache.
    470     env->CallIntMethod(db.jniInfo.jContextHubService,
    471                        db.jniInfo.contextHubServiceAddAppInstance,
    472                        hubHandle, entry.instanceId,
    473                        entry.truncName,
    474                        entry.appInfo.version);
    475 
    476     const char *action = (db.appInstances.count(appInstanceHandle) == 0) ? "Added" : "Updated";
    477     ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
    478           " as appInstance %" PRId32, action, entry.truncName,
    479           entry.hubHandle, appInstanceHandle);
    480 
    481     return appInstanceHandle;
    482 }
    483 
    484 int deleteAppInstance(jint id, JNIEnv *env) {
    485     bool fullyDeleted = true;
    486 
    487     if (db.appInstances.count(id)) {
    488         db.appInstances.erase(id);
    489     } else {
    490         ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
    491         fullyDeleted = false;
    492     }
    493     returnId(id);
    494 
    495     if ((env == nullptr) ||
    496         (env->CallIntMethod(db.jniInfo.jContextHubService,
    497                        db.jniInfo.contextHubServiceDeleteAppInstance,
    498                        id) != 0)) {
    499         ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
    500         fullyDeleted = false;
    501     }
    502 
    503     if (fullyDeleted) {
    504         ALOGI("Deleted App id : %" PRId32, id);
    505         return 0;
    506     }
    507     return -1;
    508 }
    509 
    510 int startLoadAppTxn(uint64_t appId, int hubHandle) {
    511     AppInstanceInfo *txnInfo = new AppInstanceInfo();
    512     jint instanceId = generateId();
    513 
    514     if (!txnInfo || instanceId < 0) {
    515         returnId(instanceId);
    516         free(txnInfo);
    517         return -1;
    518     }
    519 
    520     txnInfo->truncName = appId;
    521     txnInfo->hubHandle = hubHandle;
    522     txnInfo->instanceId = instanceId;
    523 
    524     txnInfo->appInfo.appId = appId;
    525     txnInfo->appInfo.version = -1; // Awaited
    526 
    527     if (db.txnManager.addTxn(CONTEXT_HUB_LOAD_APP, txnInfo) != 0) {
    528         returnId(instanceId);
    529         free(txnInfo);
    530         return -1;
    531     }
    532 
    533     return 0;
    534 }
    535 
    536 int startUnloadAppTxn(jint appInstanceHandle) {
    537     jint *txnData = new(jint);
    538     if (!txnData) {
    539         ALOGW("Cannot allocate memory to start unload transaction");
    540         return -1;
    541     }
    542 
    543     *txnData = appInstanceHandle;
    544 
    545     if (db.txnManager.addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) {
    546         free(txnData);
    547         ALOGW("Cannot start transaction to unload app");
    548         return -1;
    549     }
    550 
    551     return 0;
    552 }
    553 
    554 void getHubsCb(const ::android::hardware::hidl_vec<ContextHub>& hubs)  {
    555     for (size_t i = 0; i < hubs.size(); i++) {
    556         db.hubInfo.hubs.push_back(hubs[i]);
    557     }
    558 }
    559 
    560 void initContextHubService() {
    561     db.hubInfo.numHubs = 0;
    562 
    563     db.hubInfo.contextHub = IContexthub::getService();
    564 
    565     if (db.hubInfo.contextHub == nullptr) {
    566         ALOGE("Could not load context hub hal");
    567     } else {
    568         ALOGI("Loaded context hub hal, isRemote %s", db.hubInfo.contextHub->isRemote() ? "TRUE" : "FALSE");
    569     }
    570 
    571     // Prep for storing app info
    572     for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
    573         db.freeIds.push(i);
    574     }
    575 
    576     if (db.hubInfo.contextHub != nullptr) {
    577         std::function<void(const ::android::hardware::hidl_vec<ContextHub>& hubs)> f = getHubsCb;
    578         if(!db.hubInfo.contextHub->getHubs(f).isOk()) {
    579             ALOGW("GetHubs Failed! transport error.");
    580             return;
    581         };
    582 
    583         int retNumHubs = db.hubInfo.hubs.size();
    584         ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
    585         db.hubInfo.numHubs = retNumHubs;
    586 
    587         for (int i = 0; i < db.hubInfo.numHubs; i++) {
    588             ALOGI("Subscribing to hubHandle %d", i);
    589 
    590             ContextHubServiceCallback *callBackPtr =
    591                 new ContextHubServiceCallback(db.hubInfo.hubs[i].hubId);
    592             db.hubInfo.contextHub->registerCallback(db.hubInfo.hubs[i].hubId,
    593                                                     callBackPtr);
    594             db.regCallBacks.push_back(callBackPtr);
    595         }
    596 
    597         sendQueryForApps();
    598 
    599     } else {
    600         ALOGW("No Context Hub Module present");
    601     }
    602 }
    603 
    604 void onHubReset(uint32_t hubId) {
    605     TransactionResult result = TransactionResult::SUCCESS;
    606     db.txnManager.closeTxn();
    607     // TODO : Expose this through an api
    608     passOnOsResponse(hubId, CONTEXT_HUB_OS_REBOOT, result, nullptr, 0);
    609     queryHubForApps(hubId);
    610 }
    611 
    612 int onMessageReceipt(const uint32_t *header,
    613                      size_t headerLen,
    614                      const char *msg,
    615                      size_t msgLen) {
    616     JNIEnv *env;
    617 
    618     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    619       return -1;
    620     }
    621 
    622     jbyteArray jmsg = env->NewByteArray(msgLen);
    623     if (jmsg == nullptr) {
    624         ALOGW("Can't allocate %zu byte array", msgLen);
    625         return -1;
    626     }
    627     jintArray jheader = env->NewIntArray(headerLen);
    628     if (jheader == nullptr) {
    629         env->DeleteLocalRef(jmsg);
    630         ALOGW("Can't allocate %zu int array", headerLen);
    631         return -1;
    632     }
    633 
    634     env->SetByteArrayRegion(jmsg, 0, msgLen, reinterpret_cast<const jbyte *>(msg));
    635     env->SetIntArrayRegion(jheader, 0, headerLen, reinterpret_cast<const jint *>(header));
    636 
    637     int ret = (env->CallIntMethod(db.jniInfo.jContextHubService,
    638                                   db.jniInfo.contextHubServiceMsgReceiptCallback,
    639                                   jheader,
    640                                   jmsg) != 0);
    641     env->DeleteLocalRef(jmsg);
    642     env->DeleteLocalRef(jheader);
    643 
    644     return ret;
    645 }
    646 
    647 int handleQueryAppsResponse(const std::vector<HubAppInfo> apps,
    648                                uint32_t hubHandle) {
    649     JNIEnv *env;
    650     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    651             return -1;
    652     }
    653 
    654     int numApps = apps.size();
    655 
    656     // We use this information to sync our JNI and Java caches of nanoapp info.
    657     // We want to accomplish two things here:
    658     // 1) Remove entries from our caches which are stale, and pertained to
    659     //    apps no longer running on Context Hub.
    660     // 2) Populate our caches with the latest information of all these apps.
    661 
    662     // We make a couple of assumptions here:
    663     // A) The JNI and Java caches are in sync with each other (this isn't
    664     //    necessarily true; any failure of a single call into Java land to
    665     //    update its cache will leave that cache in a bad state.  For NYC,
    666     //    we're willing to tolerate this for now).
    667     // B) The total number of apps is relatively small, so horribly inefficent
    668     //    algorithms aren't too painful.
    669     // C) We're going to call this relatively infrequently, so its inefficency
    670     //    isn't a big impact.
    671 
    672 
    673     // (1).  Looking for stale cache entries.  Yes, this is O(N^2).  See
    674     // assumption (B).  Per assumption (A), it is sufficient to iterate
    675     // over just the JNI cache.
    676     auto end = db.appInstances.end();
    677     for (auto current = db.appInstances.begin(); current != end; ) {
    678         AppInstanceInfo cacheEntry = current->second;
    679         // We perform our iteration here because if we call
    680         // delete_app_instance() below, it will erase() this entry.
    681         current++;
    682         bool entryIsStale = true;
    683         for (int i = 0; i < numApps; i++) {
    684             if (apps[i].appId == cacheEntry.appInfo.appId) {
    685                 // We found a match; this entry is current.
    686                 entryIsStale = false;
    687                 break;
    688             }
    689         }
    690 
    691         if (entryIsStale) {
    692             deleteAppInstance(cacheEntry.instanceId, env);
    693         }
    694     }
    695 
    696     // (2).  Update our caches with the latest.
    697     for (int i = 0; i < numApps; i++) {
    698         // We will only have one instance of the app
    699         // TODO : Change this logic once we support multiple instances of the same app
    700         jint appInstance = getAppInstanceForAppId(apps[i].appId);
    701         if (appInstance == -1) {
    702             // This is a previously unknown app, let's allocate an "id" for it.
    703             appInstance = generateId();
    704         }
    705         addAppInstance(&apps[i], hubHandle, appInstance, env);
    706     }
    707     return 0;
    708 }
    709 
    710 // TODO(b/30807327): Do not use raw bytes for additional data.  Use the
    711 //     JNI interfaces for the appropriate types.
    712 void passOnOsResponse(uint32_t hubHandle,
    713                       uint32_t msgType,
    714                       TransactionResult result,
    715                       const int8_t *additionalData,
    716                       size_t additionalDataLen) {
    717     JNIEnv *env;
    718 
    719     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    720         ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32,
    721               msgType);
    722         return;
    723     }
    724 
    725     uint32_t header[MSG_HEADER_SIZE];
    726     memset(header, 0, sizeof(header));
    727 
    728     if (!additionalData) {
    729         additionalDataLen = 0; // clamp
    730     }
    731     int msgLen = 1 + additionalDataLen;
    732 
    733     int8_t *msg = new int8_t[msgLen];
    734 
    735     if (!msg) {
    736         ALOGW("Unexpected : Ran out of memory, cannot send response");
    737         return;
    738     }
    739 
    740     header[HEADER_FIELD_MSG_TYPE] = msgType;
    741     header[HEADER_FIELD_MSG_VERSION] = 0;
    742     header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
    743     header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
    744 
    745     // Due to API constraints, at the moment we can't change the fact that
    746     // we're changing our 4-byte response to a 1-byte value.  But we can prevent
    747     // the possible change in sign (and thus meaning) that would happen from
    748     // a naive cast.  Further, we can log when we're losing part of the value.
    749     // TODO(b/30918279): Don't truncate this result.
    750     int8_t truncatedResult;
    751     truncatedResult = static_cast<int8_t>(result);
    752     msg[0] = truncatedResult;
    753 
    754     if (additionalData) {
    755         memcpy(&msg[1], additionalData, additionalDataLen);
    756     }
    757 
    758     jbyteArray jmsg = env->NewByteArray(msgLen);
    759     jintArray jheader = env->NewIntArray(arraysize(header));
    760 
    761     env->SetByteArrayRegion(jmsg, 0, msgLen, reinterpret_cast<jbyte *>(msg));
    762     env->SetIntArrayRegion(jheader, 0, arraysize(header), reinterpret_cast<jint *>(header));
    763 
    764     ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
    765           header[HEADER_FIELD_MSG_TYPE],
    766           header[HEADER_FIELD_APP_INSTANCE],
    767           header[HEADER_FIELD_HUB_HANDLE]);
    768 
    769     env->CallIntMethod(db.jniInfo.jContextHubService,
    770                        db.jniInfo.contextHubServiceMsgReceiptCallback,
    771                        jheader,
    772                        jmsg);
    773 
    774     env->DeleteLocalRef(jmsg);
    775     env->DeleteLocalRef(jheader);
    776 
    777     delete[] msg;
    778 }
    779 
    780 void closeUnloadTxn(bool success) {
    781     void *txnData = nullptr;
    782     HubMessageType txnId;
    783 
    784     if (success && db.txnManager.fetchTxnData(&txnId, &txnData) == 0 &&
    785         txnId == CONTEXT_HUB_UNLOAD_APP) {
    786         JNIEnv *env;
    787         if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    788             ALOGW("Could not attach to JVM !");
    789             env = nullptr;
    790         }
    791         jint handle = *reinterpret_cast<jint *>(txnData);
    792         deleteAppInstance(handle, env);
    793     } else {
    794         ALOGW("Could not unload the app successfully ! success %d, txnData %p",
    795               success,
    796               txnData);
    797     }
    798 
    799     db.txnManager.closeTxn();
    800 }
    801 
    802 bool closeLoadTxn(bool success, jint *appInstanceHandle) {
    803     void *txnData;
    804     HubMessageType txnId;
    805 
    806     if (success && db.txnManager.fetchTxnData(&txnId, &txnData) == 0 &&
    807         txnId == CONTEXT_HUB_LOAD_APP) {
    808         AppInstanceInfo *info = static_cast<AppInstanceInfo *>(txnData);
    809         *appInstanceHandle = info->instanceId;
    810 
    811         JNIEnv *env;
    812         if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) {
    813             addAppInstance(&info->appInfo, info->hubHandle, info->instanceId, env);
    814         } else {
    815             ALOGW("Could not attach to JVM !");
    816             success = false;
    817         }
    818         // While we just called addAppInstance above, our info->appInfo was
    819         // incomplete (for example, the 'version' is hardcoded to -1).  So we
    820         // trigger an additional query to the CHRE, so we'll be able to get
    821         // all the app "info", and have our JNI and Java caches with the
    822         // full information.
    823         sendQueryForApps();
    824     } else {
    825         ALOGW("Could not load the app successfully ! Unexpected failure");
    826         *appInstanceHandle = INVALID_APP_ID;
    827         success = false;
    828     }
    829 
    830     db.txnManager.closeTxn();
    831     return success;
    832 }
    833 
    834 int initJni(JNIEnv *env, jobject instance) {
    835     if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
    836         return -1;
    837     }
    838 
    839     db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
    840 
    841     db.jniInfo.contextHubInfoClass =
    842             env->FindClass("android/hardware/location/ContextHubInfo");
    843     db.jniInfo.contextHubServiceClass =
    844             env->FindClass("com/android/server/location/ContextHubService");
    845 
    846     db.jniInfo.memoryRegionsClass =
    847             env->FindClass("android/hardware/location/MemoryRegion");
    848 
    849     db.jniInfo.contextHubInfoCtor =
    850             env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
    851     db.jniInfo.contextHubInfoSetId =
    852             env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
    853     db.jniInfo.contextHubInfoSetName =
    854             env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName", "(Ljava/lang/String;)V");
    855     db.jniInfo.contextHubInfoSetVendor =
    856             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    857                              "setVendor",
    858                              "(Ljava/lang/String;)V");
    859     db.jniInfo.contextHubInfoSetToolchain =
    860             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    861                              "setToolchain",
    862                              "(Ljava/lang/String;)V");
    863     db.jniInfo.contextHubInfoSetPlatformVersion =
    864             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    865                              "setPlatformVersion",
    866                              "(I)V");
    867     db.jniInfo.contextHubInfoSetStaticSwVersion =
    868             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    869                              "setStaticSwVersion",
    870                              "(I)V");
    871     db.jniInfo.contextHubInfoSetToolchainVersion =
    872             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    873                              "setToolchainVersion",
    874                              "(I)V");
    875     db.jniInfo.contextHubInfoSetPeakMips =
    876             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    877                              "setPeakMips",
    878                              "(F)V");
    879     db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
    880             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    881                              "setStoppedPowerDrawMw",
    882                              "(F)V");
    883     db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
    884             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    885                              "setSleepPowerDrawMw",
    886                              "(F)V");
    887     db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
    888             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    889                              "setPeakPowerDrawMw",
    890                              "(F)V");
    891     db.jniInfo.contextHubInfoSetSupportedSensors =
    892             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    893                              "setSupportedSensors",
    894                              "([I)V");
    895     db.jniInfo.contextHubInfoSetMemoryRegions =
    896             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    897                              "setMemoryRegions",
    898                              "([Landroid/hardware/location/MemoryRegion;)V");
    899     db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
    900              env->GetMethodID(db.jniInfo.contextHubInfoClass,
    901                               "setMaxPacketLenBytes",
    902                               "(I)V");
    903     db.jniInfo.contextHubServiceMsgReceiptCallback =
    904             env->GetMethodID(db.jniInfo.contextHubServiceClass,
    905                              "onMessageReceipt",
    906                              "([I[B)I");
    907     db.jniInfo.contextHubInfoSetName =
    908             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    909                              "setName",
    910                              "(Ljava/lang/String;)V");
    911     db.jniInfo.contextHubServiceAddAppInstance =
    912                  env->GetMethodID(db.jniInfo.contextHubServiceClass,
    913                                   "addAppInstance",
    914                                   "(IIJI)I");
    915     db.jniInfo.contextHubServiceDeleteAppInstance =
    916                  env->GetMethodID(db.jniInfo.contextHubServiceClass,
    917                                   "deleteAppInstance",
    918                                   "(I)I");
    919 
    920     return 0;
    921 }
    922 
    923 jobject constructJContextHubInfo(JNIEnv *env, const ContextHub &hub) {
    924     jstring jstrBuf;
    925     jintArray jintBuf;
    926     jobjectArray jmemBuf;
    927 
    928     jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
    929                                   db.jniInfo.contextHubInfoCtor);
    930     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub.hubId);
    931 
    932     jstrBuf = env->NewStringUTF(hub.name.c_str());
    933     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
    934     env->DeleteLocalRef(jstrBuf);
    935 
    936     jstrBuf = env->NewStringUTF(hub.vendor.c_str());
    937     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
    938     env->DeleteLocalRef(jstrBuf);
    939 
    940     jstrBuf = env->NewStringUTF(hub.toolchain.c_str());
    941     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
    942     env->DeleteLocalRef(jstrBuf);
    943 
    944     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub.platformVersion);
    945     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub.toolchainVersion);
    946     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub.peakMips);
    947     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
    948                         hub.stoppedPowerDrawMw);
    949     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
    950                         hub.sleepPowerDrawMw);
    951     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
    952                         hub.peakPowerDrawMw);
    953     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
    954                         hub.maxSupportedMsgLen);
    955 
    956 
    957     jintBuf = env->NewIntArray(hub.connectedSensors.size());
    958     int *connectedSensors = new int[hub.connectedSensors.size()];
    959 
    960     if (!connectedSensors) {
    961       ALOGW("Cannot allocate memory! Unexpected");
    962       assert(false);
    963     } else {
    964       for (unsigned int i = 0; i < hub.connectedSensors.size(); i++) {
    965         // TODO :: Populate connected sensors.
    966         //connectedSensors[i] = hub.connectedSensors[i].sensorType;
    967         connectedSensors[i] = 0;
    968       }
    969     }
    970 
    971     env->SetIntArrayRegion(jintBuf, 0, hub.connectedSensors.size(),
    972                            connectedSensors);
    973 
    974     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
    975     env->DeleteLocalRef(jintBuf);
    976 
    977     // We are not getting the memory regions from the CH Hal - change this when it is available
    978     jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
    979     // Note the zero size above. We do not need to set any elements
    980     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
    981     env->DeleteLocalRef(jmemBuf);
    982 
    983 
    984     delete[] connectedSensors;
    985     return jHub;
    986 }
    987 
    988 jobjectArray nativeInitialize(JNIEnv *env, jobject instance) {
    989     jobject hub;
    990     jobjectArray retArray;
    991 
    992     if (initJni(env, instance) < 0) {
    993         return nullptr;
    994     }
    995 
    996     initContextHubService();
    997 
    998     if (db.hubInfo.numHubs > 1) {
    999         ALOGW("Clamping the number of hubs to 1");
   1000         db.hubInfo.numHubs = 1;
   1001     }
   1002 
   1003     retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
   1004 
   1005     for(int i = 0; i < db.hubInfo.numHubs; i++) {
   1006         hub = constructJContextHubInfo(env, db.hubInfo.hubs[i]);
   1007         env->SetObjectArrayElement(retArray, i, hub);
   1008     }
   1009 
   1010     return retArray;
   1011 }
   1012 
   1013 Result sendLoadNanoAppRequest(uint32_t hubId,
   1014                               jbyte *data,
   1015                               size_t dataBufferLength) {
   1016     auto header = reinterpret_cast<const NanoAppBinaryHeader *>(data);
   1017     Result result;
   1018 
   1019     if (dataBufferLength < sizeof(NanoAppBinaryHeader)) {
   1020         ALOGE("Got short NanoApp, length %zu", dataBufferLength);
   1021         result = Result::BAD_PARAMS;
   1022     } else if (header->headerVersion != htole32(kNanoAppBinaryHeaderVersion)) {
   1023         ALOGE("Got unexpected NanoApp header version %" PRIu32,
   1024               letoh32(header->headerVersion));
   1025         result = Result::BAD_PARAMS;
   1026     } else {
   1027         NanoAppBinary nanoapp;
   1028 
   1029         // Data from the common nanoapp header goes into explicit fields
   1030         nanoapp.appId      = letoh64(header->appId);
   1031         nanoapp.appVersion = letoh32(header->appVersion);
   1032         nanoapp.flags      = letoh32(header->flags);
   1033         nanoapp.targetChreApiMajorVersion = header->targetChreApiMajorVersion;
   1034         nanoapp.targetChreApiMinorVersion = header->targetChreApiMinorVersion;
   1035 
   1036         // Everything past the header goes in customBinary
   1037         auto dataBytes = reinterpret_cast<const uint8_t *>(data);
   1038         std::vector<uint8_t> customBinary(
   1039             dataBytes + sizeof(NanoAppBinaryHeader),
   1040             dataBytes + dataBufferLength);
   1041         nanoapp.customBinary = std::move(customBinary);
   1042 
   1043         ALOGW("Calling Load NanoApp on hub %d", hubId);
   1044         result = db.hubInfo.contextHub->loadNanoApp(hubId,
   1045                                                     nanoapp,
   1046                                                     CONTEXT_HUB_LOAD_APP);
   1047     }
   1048 
   1049     return result;
   1050 }
   1051 
   1052 jint nativeSendMessage(JNIEnv *env,
   1053                        jobject instance,
   1054                        jintArray header_,
   1055                        jbyteArray data_) {
   1056     // With the new binderized HAL definition, this function can be made much simpler.
   1057     // All the magic can be removed. This is not however needed for the default implementation
   1058     // TODO :: Change the JNI interface to conform to the new HAL interface and clean up this
   1059     // function
   1060     jint retVal = -1; // Default to failure
   1061 
   1062     jint *header = env->GetIntArrayElements(header_, 0);
   1063     size_t numHeaderElements = env->GetArrayLength(header_);
   1064     jbyte *data = env->GetByteArrayElements(data_, 0);
   1065     size_t dataBufferLength = env->GetArrayLength(data_);
   1066 
   1067     if (numHeaderElements < MSG_HEADER_SIZE) {
   1068         ALOGW("Malformed header len");
   1069         return -1;
   1070     }
   1071 
   1072     jint appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
   1073     uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
   1074     int hubHandle = -1;
   1075     uint64_t appId;
   1076 
   1077     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1078         hubHandle = getHubHandleForAppInstance(appInstanceHandle);
   1079     } else if (msgType == CONTEXT_HUB_LOAD_APP) {
   1080         if (numHeaderElements < MSG_HEADER_SIZE_LOAD_APP) {
   1081             return -1;
   1082         }
   1083         uint64_t appIdLo = header[HEADER_FIELD_LOAD_APP_ID_LO];
   1084         uint64_t appIdHi = header[HEADER_FIELD_LOAD_APP_ID_HI];
   1085         appId = appIdHi << 32 | appIdLo;
   1086 
   1087         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
   1088     } else {
   1089         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
   1090     }
   1091 
   1092     uint32_t hubId = -1;
   1093     if (!getHubIdForHubHandle(hubHandle, &hubId)) {
   1094         ALOGD("Invalid hub Handle %d", hubHandle);
   1095         return -1;
   1096     }
   1097 
   1098     if (msgType == CONTEXT_HUB_LOAD_APP ||
   1099         msgType == CONTEXT_HUB_UNLOAD_APP) {
   1100 
   1101         db.txnManager.closeAnyStaleTxns();
   1102 
   1103         if (db.txnManager.isTxnPending()) {
   1104             // TODO : There is a race conditio
   1105             ALOGW("Cannot load or unload app while a transaction is pending !");
   1106             return -1;
   1107         } else if (msgType == CONTEXT_HUB_LOAD_APP) {
   1108             if (startLoadAppTxn(appId, hubHandle) != 0) {
   1109                 ALOGW("Cannot Start Load Transaction");
   1110                 return -1;
   1111             }
   1112         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1113             if (startUnloadAppTxn(appInstanceHandle) != 0) {
   1114                 ALOGW("Cannot Start UnLoad Transaction");
   1115                 return -1;
   1116             }
   1117         }
   1118     }
   1119 
   1120     Result result;
   1121 
   1122     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1123         ALOGW("Calling UnLoad NanoApp for app %" PRIx64 " on hub %" PRIu32,
   1124               db.appInstances[appInstanceHandle].appInfo.appId,
   1125               hubId);
   1126         result = db.hubInfo.contextHub->unloadNanoApp(
   1127                 hubId, db.appInstances[appInstanceHandle].appInfo.appId, CONTEXT_HUB_UNLOAD_APP);
   1128     } else {
   1129         if (appInstanceHandle == OS_APP_ID) {
   1130             if (msgType == CONTEXT_HUB_LOAD_APP) {
   1131                 result = sendLoadNanoAppRequest(hubId, data, dataBufferLength);
   1132             } else if (msgType == CONTEXT_HUB_QUERY_APPS) {
   1133                 result = db.hubInfo.contextHub->queryApps(hubId);
   1134             } else {
   1135                 ALOGD("Dropping OS addresses message of type - %" PRIu32, msgType);
   1136                 result = Result::BAD_PARAMS;
   1137             }
   1138         } else {
   1139             appId = getAppIdForAppInstance(appInstanceHandle);
   1140             if (appId == static_cast<uint64_t>(INVALID_APP_ID)) {
   1141                 ALOGD("Cannot find application instance %d", appInstanceHandle);
   1142                 result = Result::BAD_PARAMS;
   1143             } else if (hubHandle != getHubHandleForAppInstance(appInstanceHandle)) {
   1144                 ALOGE("Given hubHandle (%d) doesn't match expected for app instance (%d)",
   1145                       hubHandle,
   1146                       getHubHandleForAppInstance(appInstanceHandle));
   1147                 result = Result::BAD_PARAMS;
   1148             } else {
   1149                 ContextHubMsg msg;
   1150                 msg.appName = appId;
   1151                 msg.msgType = msgType;
   1152                 msg.msg.setToExternal((unsigned char *)data, dataBufferLength);
   1153 
   1154                 ALOGW("Sending msg of type %" PRIu32 " len %zu to app %" PRIx64 " on hub %" PRIu32,
   1155                        msgType,
   1156                        dataBufferLength,
   1157                        appId,
   1158                        hubId);
   1159                 result = db.hubInfo.contextHub->sendMessageToHub(hubId, msg);
   1160             }
   1161         }
   1162     }
   1163 
   1164     if (result != Result::OK) {
   1165         ALOGD("Send Message failure - %d", retVal);
   1166         if (msgType == CONTEXT_HUB_LOAD_APP) {
   1167             jint ignored;
   1168             closeLoadTxn(false, &ignored);
   1169         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1170             closeUnloadTxn(false);
   1171         }
   1172     } else {
   1173         retVal = 0;
   1174     }
   1175 
   1176     env->ReleaseIntArrayElements(header_, header, 0);
   1177     env->ReleaseByteArrayElements(data_, data, 0);
   1178 
   1179     return retVal;
   1180 }
   1181 
   1182 //--------------------------------------------------------------------------------------------------
   1183 //
   1184 const JNINativeMethod gContextHubServiceMethods[] = {
   1185     {"nativeInitialize",
   1186             "()[Landroid/hardware/location/ContextHubInfo;",
   1187             reinterpret_cast<void*>(nativeInitialize)},
   1188     {"nativeSendMessage",
   1189             "([I[B)I",
   1190             reinterpret_cast<void*>(nativeSendMessage)}
   1191 };
   1192 
   1193 int register_android_server_location_ContextHubService(JNIEnv *env)
   1194 {
   1195     RegisterMethodsOrDie(env, "com/android/server/location/ContextHubService",
   1196             gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
   1197 
   1198     return 0;
   1199 }
   1200 
   1201 }//namespace android
   1202