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 #include "context_hub.h"
     18 
     19 #define LOG_NDEBUG 0
     20 #define LOG_TAG "ContextHubService"
     21 
     22 #include <inttypes.h>
     23 #include <jni.h>
     24 #include <mutex>
     25 #include <string.h>
     26 #include <stdint.h>
     27 #include <stdio.h>
     28 #include <stdlib.h>
     29 
     30 // TOOD: On master, alphabetize these and move <mutex> into this
     31 //     grouping.
     32 #include <chrono>
     33 #include <unordered_map>
     34 #include <queue>
     35 
     36 #include <cutils/log.h>
     37 
     38 #include "JNIHelp.h"
     39 #include "core_jni_helpers.h"
     40 
     41 static constexpr jint OS_APP_ID = -1;
     42 static constexpr jint INVALID_APP_ID = -2;
     43 static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
     44 
     45 static constexpr jint MIN_APP_ID = 1;
     46 static constexpr jint MAX_APP_ID = 128;
     47 
     48 static constexpr size_t MSG_HEADER_SIZE = 4;
     49 static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
     50 static constexpr size_t HEADER_FIELD_MSG_VERSION = 1;
     51 static constexpr size_t HEADER_FIELD_HUB_HANDLE = 2;
     52 static constexpr size_t HEADER_FIELD_APP_INSTANCE = 3;
     53 
     54 static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
     55 static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
     56 static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
     57 
     58 // Monotonically increasing clock we use to determine if we can cancel
     59 // a transaction.
     60 using std::chrono::steady_clock;
     61 
     62 namespace android {
     63 
     64 namespace {
     65 
     66 /*
     67  * Finds the length of a statically-sized array using template trickery that
     68  * also prevents it from being applied to the wrong type.
     69  */
     70 template <typename T, size_t N>
     71 constexpr size_t array_length(T (&)[N]) { return N; }
     72 
     73 struct jniInfo_s {
     74     JavaVM *vm;
     75     jclass contextHubInfoClass;
     76     jclass contextHubServiceClass;
     77     jclass memoryRegionsClass;
     78 
     79     jobject jContextHubService;
     80 
     81     jmethodID msgReceiptCallBack;
     82 
     83     jmethodID contextHubInfoCtor;
     84     jmethodID contextHubInfoSetId;
     85     jmethodID contextHubInfoSetName;
     86     jmethodID contextHubInfoSetVendor;
     87     jmethodID contextHubInfoSetToolchain;
     88     jmethodID contextHubInfoSetPlatformVersion;
     89     jmethodID contextHubInfoSetStaticSwVersion;
     90     jmethodID contextHubInfoSetToolchainVersion;
     91     jmethodID contextHubInfoSetPeakMips;
     92     jmethodID contextHubInfoSetStoppedPowerDrawMw;
     93     jmethodID contextHubInfoSetSleepPowerDrawMw;
     94     jmethodID contextHubInfoSetPeakPowerDrawMw;
     95     jmethodID contextHubInfoSetSupportedSensors;
     96     jmethodID contextHubInfoSetMemoryRegions;
     97     jmethodID contextHubInfoSetMaxPacketLenBytes;
     98 
     99     jmethodID contextHubServiceMsgReceiptCallback;
    100     jmethodID contextHubServiceAddAppInstance;
    101     jmethodID contextHubServiceDeleteAppInstance;
    102 };
    103 
    104 struct context_hub_info_s {
    105     uint32_t *cookies;
    106     int numHubs;
    107     const struct context_hub_t *hubs;
    108     struct context_hub_module_t *contextHubModule;
    109 };
    110 
    111 struct app_instance_info_s {
    112     uint64_t truncName;          // Possibly truncated name for logging
    113     uint32_t hubHandle;          // Id of the hub this app is on
    114     jint instanceId;             // system wide unique instance id - assigned
    115     struct hub_app_info appInfo; // returned from the HAL
    116 };
    117 
    118 
    119 // If a transaction takes longer than this, we'll allow it to be
    120 // canceled by a new transaction.  Note we do _not_ automatically
    121 // cancel a transaction after this much time.  We can have a
    122 // legal transaction which takes longer than this amount of time,
    123 // as long as no other new transactions are attempted after this
    124 // time has expired.
    125 // TODO(b/31105001): Establish a clean timing approach for all
    126 // of our HAL interactions.
    127 constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
    128 
    129 /*
    130  * TODO(ashutoshj): From original code review:
    131  *
    132  * So, I feel like we could possible do a better job of organizing this code,
    133  * and being more C++-y.  Consider something like this:
    134  * class TxnManager {
    135  *  public:
    136  *   TxnManager();
    137  *   ~TxnManager();
    138  *   int add(hub_message_e identifier, void *data);
    139  *   int close();
    140  *   bool isPending() const;
    141  *   int fetchData(hub_message_e *identifier, void **data) const;
    142  *
    143  *  private:
    144  *   bool mPending;
    145  *   mutable std::mutex mLock;
    146  *   hub_message_e mIdentifier;
    147  *   void *mData;
    148  * };
    149  *
    150  * And then, for example, we'd have things like:
    151  * TxnManager::TxnManager() : mPending(false), mLock(), mIdentifier(), mData(nullptr) {}
    152  * int TxnManager::add(hub_message_e identifier, void *data) {
    153  *    std::lock_guard<std::mutex> lock(mLock);
    154  *    mPending = true;
    155  *    mData = txnData;
    156  *    mIdentifier = txnIdentifier;
    157  *    return 0;
    158  *  }
    159  * And then calling code would look like:
    160  *    if (!db.txnManager.add(CONTEXT_HUB_LOAD_APP, txnInfo)) {
    161  *
    162  * This would make it clearer the nothing is manipulating any state within TxnManager
    163  * unsafely and outside of these couple of calls.
    164  */
    165 struct txnManager_s {
    166     bool txnPending;              // Is a transaction pending
    167     std::mutex m;                 // mutex for manager
    168     hub_messages_e txnIdentifier; // What are we doing
    169     void *txnData;                // Details
    170     steady_clock::time_point firstTimeTxnCanBeCanceled;
    171 };
    172 
    173 struct contextHubServiceDb_s {
    174     int initialized;
    175     context_hub_info_s hubInfo;
    176     jniInfo_s jniInfo;
    177     std::queue<jint> freeIds;
    178     std::unordered_map<jint, app_instance_info_s> appInstances;
    179     txnManager_s txnManager;
    180 };
    181 
    182 }  // unnamed namespace
    183 
    184 static contextHubServiceDb_s db;
    185 
    186 static bool initTxnManager() {
    187     txnManager_s *mgr = &db.txnManager;
    188 
    189     mgr->txnData = nullptr;
    190     mgr->txnPending = false;
    191     return true;
    192 }
    193 
    194 static int addTxn(hub_messages_e txnIdentifier, void *txnData) {
    195     txnManager_s *mgr = &db.txnManager;
    196 
    197     std::lock_guard<std::mutex>lock(mgr->m);
    198 
    199     mgr->txnPending = true;
    200     mgr->firstTimeTxnCanBeCanceled = steady_clock::now() +
    201         kMinTransactionCancelTime;
    202     mgr->txnData = txnData;
    203     mgr->txnIdentifier = txnIdentifier;
    204 
    205     return 0;
    206 }
    207 
    208 // Only call this if you hold the db.txnManager.m lock.
    209 static void closeTxnUnlocked() {
    210     txnManager_s *mgr = &db.txnManager;
    211     mgr->txnPending = false;
    212     free(mgr->txnData);
    213     mgr->txnData = nullptr;
    214 }
    215 
    216 static int closeTxn() {
    217     std::lock_guard<std::mutex>lock(db.txnManager.m);
    218     closeTxnUnlocked();
    219     return 0;
    220 }
    221 
    222 // If a transaction has been pending for longer than
    223 // kMinTransactionCancelTime, this call will "cancel" that
    224 // transaction and return that there are none pending.
    225 static bool isTxnPending() {
    226     txnManager_s *mgr = &db.txnManager;
    227     std::lock_guard<std::mutex>lock(mgr->m);
    228     if (mgr->txnPending) {
    229         if (steady_clock::now() >= mgr->firstTimeTxnCanBeCanceled) {
    230             ALOGW("Transaction canceled");
    231             closeTxnUnlocked();
    232         }
    233     }
    234     return mgr->txnPending;
    235 }
    236 
    237 static int fetchTxnData(hub_messages_e *id, void **data) {
    238     txnManager_s *mgr = &db.txnManager;
    239 
    240     if (!id || !data) {
    241         ALOGW("Null params id %p, data %p", id, data);
    242         return -1;
    243     }
    244 
    245     std::lock_guard<std::mutex>lock(mgr->m);
    246     if (!mgr->txnPending) {
    247         ALOGW("No Transactions pending");
    248         return -1;
    249     }
    250 
    251     // else
    252     *id = mgr->txnIdentifier;
    253     *data = mgr->txnData;
    254     return 0;
    255 }
    256 
    257 int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
    258                          void *cookie);
    259 
    260 const context_hub_t *get_hub_info(int hubHandle) {
    261     if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
    262         return &db.hubInfo.hubs[hubHandle];
    263     }
    264     return nullptr;
    265 }
    266 
    267 static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
    268     const context_hub_t *info = get_hub_info(hubHandle);
    269 
    270     if (info) {
    271         return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
    272     } else {
    273         ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
    274         return -1;
    275     }
    276 }
    277 
    278 static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
    279     const context_hub_t *info = get_hub_info(hubHandle);
    280 
    281     if (info) {
    282         msg->app_name = info->os_app_name;
    283         return 0;
    284     } else {
    285         ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
    286         return -1;
    287     }
    288 }
    289 
    290 static int get_hub_id_for_hub_handle(int hubHandle) {
    291     if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
    292       return -1;
    293     } else {
    294       return db.hubInfo.hubs[hubHandle].hub_id;
    295     }
    296 }
    297 
    298 static int get_hub_handle_for_app_instance(jint id) {
    299     if (!db.appInstances.count(id)) {
    300         ALOGD("%s: Cannot find app for app instance %" PRId32,
    301               __FUNCTION__, id);
    302         return -1;
    303     }
    304 
    305     return db.appInstances[id].hubHandle;
    306 }
    307 
    308 static int get_hub_id_for_app_instance(jint id) {
    309     int hubHandle = get_hub_handle_for_app_instance(id);
    310 
    311     if (hubHandle < 0) {
    312         return -1;
    313     }
    314 
    315     return db.hubInfo.hubs[hubHandle].hub_id;
    316 }
    317 
    318 static jint get_app_instance_for_app_id(uint64_t app_id) {
    319     auto end = db.appInstances.end();
    320     for (auto current = db.appInstances.begin(); current != end; ++current) {
    321         if (current->second.appInfo.app_name.id == app_id) {
    322             return current->first;
    323         }
    324     }
    325     ALOGD("Cannot find app for app instance %" PRIu64 ".", app_id);
    326     return -1;
    327 }
    328 
    329 static int set_dest_app(hub_message_t *msg, jint id) {
    330     if (!db.appInstances.count(id)) {
    331         ALOGD("%s: Cannot find app for app instance %" PRId32,
    332               __FUNCTION__, id);
    333         return -1;
    334     }
    335 
    336     msg->app_name = db.appInstances[id].appInfo.app_name;
    337     return 0;
    338 }
    339 
    340 static void query_hub_for_apps(uint32_t hubHandle) {
    341     hub_message_t msg;
    342     query_apps_request_t queryMsg;
    343 
    344     // TODO(b/30835598): When we're able to tell which request our
    345     //     response matches, then we should allow this to be more
    346     //     targetted, instead of always being every app in the
    347     //     system.
    348     queryMsg.app_name.id = ALL_APPS;
    349 
    350     msg.message_type = CONTEXT_HUB_QUERY_APPS;
    351     msg.message_len  = sizeof(queryMsg);
    352     msg.message = &queryMsg;
    353 
    354     ALOGD("Sending query for apps to hub %" PRIu32, hubHandle);
    355     set_os_app_as_destination(&msg, hubHandle);
    356     if (send_msg_to_hub(&msg, hubHandle) != 0) {
    357         ALOGW("Could not query hub %" PRIu32 " for apps", hubHandle);
    358     }
    359 }
    360 
    361 static void sendQueryForApps() {
    362     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
    363         query_hub_for_apps(i);
    364     }
    365 }
    366 
    367 static int return_id(jint id) {
    368     // Note : This method is not thread safe.
    369     // id returned is guaranteed to be in use
    370     if (id >= 0) {
    371         db.freeIds.push(id);
    372         return 0;
    373     }
    374 
    375     return -1;
    376 }
    377 
    378 static jint generate_id() {
    379     // Note : This method is not thread safe.
    380     jint retVal = -1;
    381 
    382     if (!db.freeIds.empty()) {
    383         retVal = db.freeIds.front();
    384         db.freeIds.pop();
    385     }
    386 
    387     return retVal;
    388 }
    389 
    390 
    391 static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
    392         jint appInstanceHandle, JNIEnv *env) {
    393     // Not checking if the apps are indeed distinct
    394     app_instance_info_s entry;
    395     assert(appInfo);
    396 
    397     const char *action =
    398         (db.appInstances.count(appInstanceHandle) == 0) ? "Added" : "Updated";
    399 
    400     entry.appInfo = *appInfo;
    401 
    402     entry.instanceId = appInstanceHandle;
    403     entry.truncName = appInfo->app_name.id;
    404     entry.hubHandle = hubHandle;
    405 
    406     db.appInstances[appInstanceHandle] = entry;
    407 
    408     // Finally - let the service know of this app instance, to populate
    409     // the Java cache.
    410     env->CallIntMethod(db.jniInfo.jContextHubService,
    411                        db.jniInfo.contextHubServiceAddAppInstance,
    412                        hubHandle, entry.instanceId, entry.truncName,
    413                        entry.appInfo.version);
    414 
    415     ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
    416           " as appInstance %" PRId32, action, entry.truncName,
    417           entry.hubHandle, appInstanceHandle);
    418 
    419     return appInstanceHandle;
    420 }
    421 
    422 int delete_app_instance(jint id, JNIEnv *env) {
    423     bool fullyDeleted = true;
    424 
    425     if (db.appInstances.count(id)) {
    426         db.appInstances.erase(id);
    427     } else {
    428         ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
    429         fullyDeleted = false;
    430     }
    431     return_id(id);
    432 
    433     if ((env == nullptr) ||
    434         (env->CallIntMethod(db.jniInfo.jContextHubService,
    435                        db.jniInfo.contextHubServiceDeleteAppInstance,
    436                        id) != 0)) {
    437         ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
    438         fullyDeleted = false;
    439     }
    440 
    441     if (fullyDeleted) {
    442         ALOGI("Deleted App id : %" PRId32, id);
    443         return 0;
    444     }
    445     return -1;
    446 }
    447 
    448 static int startLoadAppTxn(uint64_t appId, int hubHandle) {
    449     app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
    450     jint instanceId = generate_id();
    451 
    452     if (!txnInfo || instanceId < 0) {
    453         return_id(instanceId);
    454         free(txnInfo);
    455         return -1;
    456     }
    457 
    458     txnInfo->truncName = appId;
    459     txnInfo->hubHandle = hubHandle;
    460     txnInfo->instanceId = instanceId;
    461 
    462     txnInfo->appInfo.app_name.id = appId;
    463     txnInfo->appInfo.num_mem_ranges = 0;
    464     txnInfo->appInfo.version = -1; // Awaited
    465 
    466     if (addTxn(CONTEXT_HUB_LOAD_APP, txnInfo) != 0) {
    467         return_id(instanceId);
    468         free(txnInfo);
    469         return -1;
    470     }
    471 
    472     return 0;
    473 }
    474 
    475 static int startUnloadAppTxn(jint appInstanceHandle) {
    476     jint *txnData = (jint *) malloc(sizeof(jint));
    477     if (!txnData) {
    478         ALOGW("Cannot allocate memory to start unload transaction");
    479         return -1;
    480     }
    481 
    482     *txnData = appInstanceHandle;
    483 
    484     if (addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) {
    485         free(txnData);
    486         ALOGW("Cannot start transaction to unload app");
    487         return -1;
    488     }
    489 
    490     return 0;
    491 }
    492 
    493 static void initContextHubService() {
    494     int err = 0;
    495     db.hubInfo.hubs = nullptr;
    496     db.hubInfo.numHubs = 0;
    497 
    498     err = hw_get_module(CONTEXT_HUB_MODULE_ID,
    499                         (hw_module_t const**)(&db.hubInfo.contextHubModule));
    500 
    501     if (err) {
    502       ALOGE("** Could not load %s module : err %s", CONTEXT_HUB_MODULE_ID,
    503             strerror(-err));
    504     }
    505 
    506     // Prep for storing app info
    507     for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
    508         db.freeIds.push(i);
    509     }
    510 
    511     initTxnManager();
    512     if (db.hubInfo.contextHubModule) {
    513         int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
    514                                                                  &db.hubInfo.hubs);
    515         ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
    516         db.hubInfo.numHubs = retNumHubs;
    517 
    518         if (db.hubInfo.numHubs > 0) {
    519             db.hubInfo.numHubs = retNumHubs;
    520             db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
    521 
    522             if (!db.hubInfo.cookies) {
    523                 ALOGW("Ran out of memory allocating cookies, bailing");
    524                 return;
    525             }
    526 
    527             for (int i = 0; i < db.hubInfo.numHubs; i++) {
    528                 db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
    529                 ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
    530                 if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
    531                                                                     context_hub_callback,
    532                                                                     &db.hubInfo.cookies[i]) == 0) {
    533                 }
    534             }
    535         }
    536 
    537         sendQueryForApps();
    538     } else {
    539         ALOGW("No Context Hub Module present");
    540     }
    541 }
    542 
    543 static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_t msgLen) {
    544     JNIEnv *env;
    545 
    546     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    547       return -1;
    548     }
    549 
    550     jbyteArray jmsg = env->NewByteArray(msgLen);
    551     if (jmsg == nullptr) {
    552         ALOGW("Can't allocate %zu byte array", msgLen);
    553         return -1;
    554     }
    555     jintArray jheader = env->NewIntArray(headerLen);
    556     if (jheader == nullptr) {
    557         env->DeleteLocalRef(jmsg);
    558         ALOGW("Can't allocate %zu int array", headerLen);
    559         return -1;
    560     }
    561 
    562     env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
    563     env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
    564 
    565     int ret = (env->CallIntMethod(db.jniInfo.jContextHubService,
    566                           db.jniInfo.contextHubServiceMsgReceiptCallback,
    567                           jheader, jmsg) != 0);
    568     env->DeleteLocalRef(jmsg);
    569     env->DeleteLocalRef(jheader);
    570 
    571     return ret;
    572 }
    573 
    574 int handle_query_apps_response(const uint8_t *msg, int msgLen,
    575                                uint32_t hubHandle) {
    576     JNIEnv *env;
    577     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    578             return -1;
    579     }
    580 
    581     int numApps = msgLen / sizeof(hub_app_info);
    582     const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
    583 
    584     // We use this information to sync our JNI and Java caches of nanoapp info.
    585     // We want to accomplish two things here:
    586     // 1) Remove entries from our caches which are stale, and pertained to
    587     //    apps no longer running on Context Hub.
    588     // 2) Populate our caches with the latest information of all these apps.
    589 
    590     // We make a couple of assumptions here:
    591     // A) The JNI and Java caches are in sync with each other (this isn't
    592     //    necessarily true; any failure of a single call into Java land to
    593     //    update its cache will leave that cache in a bad state.  For NYC,
    594     //    we're willing to tolerate this for now).
    595     // B) The total number of apps is relatively small, so horribly inefficent
    596     //    algorithms aren't too painful.
    597     // C) We're going to call this relatively infrequently, so its inefficency
    598     //    isn't a big impact.
    599 
    600 
    601     // (1).  Looking for stale cache entries.  Yes, this is O(N^2).  See
    602     // assumption (B).  Per assumption (A), it is sufficient to iterate
    603     // over just the JNI cache.
    604     auto end = db.appInstances.end();
    605     for (auto current = db.appInstances.begin(); current != end; ) {
    606         app_instance_info_s cache_entry = current->second;
    607         // We perform our iteration here because if we call
    608         // delete_app_instance() below, it will erase() this entry.
    609         current++;
    610         bool entryIsStale = true;
    611         for (int i = 0; i < numApps; i++) {
    612             // We use memcmp since this could be unaligned.
    613             if (memcmp(&unalignedInfoAddr[i].app_name.id,
    614                        &cache_entry.appInfo.app_name.id,
    615                        sizeof(cache_entry.appInfo.app_name.id)) == 0) {
    616                 // We found a match; this entry is current.
    617                 entryIsStale = false;
    618                 break;
    619             }
    620         }
    621         if (entryIsStale) {
    622             delete_app_instance(cache_entry.instanceId, env);
    623         }
    624     }
    625 
    626     // (2).  Update our caches with the latest.
    627     for (int i = 0; i < numApps; i++) {
    628         hub_app_info query_info;
    629         memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
    630         // We will only have one instance of the app
    631         // TODO : Change this logic once we support multiple instances of the same app
    632         jint appInstance = get_app_instance_for_app_id(query_info.app_name.id);
    633         if (appInstance == -1) {
    634             // This is a previously unknown app, let's allocate an "id" for it.
    635             appInstance = generate_id();
    636         }
    637         add_app_instance(&query_info, hubHandle, appInstance, env);
    638     }
    639 
    640     return 0;
    641 }
    642 
    643 // TODO(b/30807327): Do not use raw bytes for additional data.  Use the
    644 //     JNI interfaces for the appropriate types.
    645 static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
    646                              status_response_t *rsp, int8_t *additionalData,
    647                              size_t additionalDataLen) {
    648     JNIEnv *env;
    649 
    650     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    651         ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32, msgType);
    652         return;
    653     }
    654 
    655     uint32_t header[MSG_HEADER_SIZE];
    656     memset(header, 0, sizeof(header));
    657 
    658     if (!additionalData) {
    659         additionalDataLen = 0; // clamp
    660     }
    661     int msgLen = 1 + additionalDataLen;
    662 
    663     int8_t *msg = new int8_t[msgLen];
    664 
    665     if (!msg) {
    666         ALOGW("Unexpected : Ran out of memory, cannot send response");
    667         return;
    668     }
    669 
    670     header[HEADER_FIELD_MSG_TYPE] = msgType;
    671     header[HEADER_FIELD_MSG_VERSION] = 0;
    672     header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
    673     header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
    674 
    675     // Due to API constraints, at the moment we can't change the fact that
    676     // we're changing our 4-byte response to a 1-byte value.  But we can prevent
    677     // the possible change in sign (and thus meaning) that would happen from
    678     // a naive cast.  Further, we can log when we're losing part of the value.
    679     // TODO(b/30918279): Don't truncate this result.
    680     int8_t truncatedResult;
    681     bool neededToTruncate;
    682     if (rsp->result < INT8_MIN) {
    683         neededToTruncate = true;
    684         truncatedResult = INT8_MIN;
    685     } else if (rsp->result > INT8_MAX) {
    686         neededToTruncate = true;
    687         truncatedResult = INT8_MAX;
    688     } else {
    689         neededToTruncate = false;
    690         // Since this value fits within an int8_t, this is a safe cast which
    691         // won't change the value or sign.
    692         truncatedResult = static_cast<int8_t>(rsp->result);
    693     }
    694     if (neededToTruncate) {
    695         ALOGW("Response from Context Hub truncated.  Value was %" PRId32
    696               ", but giving Java layer %" PRId8,
    697               rsp->result, (int)truncatedResult);
    698     }
    699 
    700     msg[0] = truncatedResult;
    701 
    702     if (additionalData) {
    703         memcpy(&msg[1], additionalData, additionalDataLen);
    704     }
    705 
    706     jbyteArray jmsg = env->NewByteArray(msgLen);
    707     jintArray jheader = env->NewIntArray(sizeof(header));
    708 
    709     env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
    710     env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
    711 
    712     ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
    713           header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE],
    714           header[HEADER_FIELD_HUB_HANDLE]);
    715 
    716     env->CallIntMethod(db.jniInfo.jContextHubService,
    717                        db.jniInfo.contextHubServiceMsgReceiptCallback,
    718                        jheader, jmsg);
    719     env->DeleteLocalRef(jmsg);
    720     env->DeleteLocalRef(jheader);
    721 
    722     delete[] msg;
    723 }
    724 
    725 void closeUnloadTxn(bool success) {
    726     void *txnData = nullptr;
    727     hub_messages_e txnId;
    728 
    729     if (success && fetchTxnData(&txnId, &txnData) == 0 &&
    730         txnId == CONTEXT_HUB_UNLOAD_APP) {
    731         JNIEnv *env;
    732         if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
    733             ALOGW("Could not attach to JVM !");
    734             env = nullptr;
    735         }
    736         jint handle = *reinterpret_cast<jint *>(txnData);
    737         delete_app_instance(handle, env);
    738     } else {
    739         ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
    740     }
    741 
    742     closeTxn();
    743 }
    744 
    745 static bool closeLoadTxn(bool success, jint *appInstanceHandle) {
    746     void *txnData;
    747     hub_messages_e txnId;
    748 
    749     if (success && fetchTxnData(&txnId, &txnData) == 0 &&
    750         txnId == CONTEXT_HUB_LOAD_APP) {
    751         app_instance_info_s *info = (app_instance_info_s *)txnData;
    752         *appInstanceHandle = info->instanceId;
    753 
    754         JNIEnv *env;
    755         if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) {
    756             add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
    757         } else {
    758             ALOGW("Could not attach to JVM !");
    759             success = false;
    760         }
    761         // While we just called add_app_instance above, our info->appInfo was
    762         // incomplete (for example, the 'version' is hardcoded to -1).  So we
    763         // trigger an additional query to the CHRE, so we'll be able to get
    764         // all the app "info", and have our JNI and Java caches with the
    765         // full information.
    766         sendQueryForApps();
    767     } else {
    768         ALOGW("Could not load the app successfully ! Unexpected failure");
    769         *appInstanceHandle = INVALID_APP_ID;
    770         success = false;
    771     }
    772 
    773     closeTxn();
    774     return success;
    775 }
    776 
    777 static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
    778                             status_response_t *rsp) {
    779     // Workaround a bug in some HALs
    780     if (msgLen == 1) {
    781         rsp->result = msg[0];
    782         return true;
    783     }
    784 
    785     if (!msg || msgLen != sizeof(*rsp)) {
    786         ALOGW("Received invalid response %p of size %zu", msg, msgLen);
    787         return false;
    788     }
    789 
    790     memcpy(rsp, msg, sizeof(*rsp));
    791 
    792     // No sanity checks on return values
    793     return true;
    794 }
    795 
    796 static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
    797                              const uint8_t *msg, int msgLen) {
    798     int retVal = -1;
    799 
    800     ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d",
    801           hubHandle, msgType, msgLen);
    802 
    803     struct status_response_t rsp;
    804 
    805     switch(msgType) {
    806 
    807       case CONTEXT_HUB_APPS_ENABLE:
    808       case CONTEXT_HUB_APPS_DISABLE:
    809       case CONTEXT_HUB_LOAD_APP:
    810       case CONTEXT_HUB_UNLOAD_APP:
    811           if (isValidOsStatus(msg, msgLen, &rsp)) {
    812               if (msgType == CONTEXT_HUB_LOAD_APP) {
    813                   jint appInstanceHandle = INVALID_APP_ID;
    814                   bool appRunningOnHub = (rsp.result == 0);
    815                   if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
    816                       if (appRunningOnHub) {
    817                           // Now we're in an odd situation.  Our nanoapp
    818                           // is up and running on the Context Hub.  However,
    819                           // something went wrong in our Service code so that
    820                           // we're not able to properly track this nanoapp
    821                           // in our Service code.  If we tell the Java layer
    822                           // things are good, it's a lie because the handle
    823                           // we give them will fail when used with the Service.
    824                           // If we tell the Java layer this failed, it's kind
    825                           // of a lie as well, since this nanoapp is running.
    826                           //
    827                           // We leave a more robust fix for later, and for
    828                           // now just tell the user things have failed.
    829                           //
    830                           // TODO(b/30835981): Make this situation better.
    831                           rsp.result = -1;
    832                       }
    833                   }
    834                   passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
    835                                    sizeof(appInstanceHandle));
    836               } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
    837                   closeUnloadTxn(rsp.result == 0);
    838                   passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
    839               } else {
    840                   passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
    841               }
    842               retVal = 0;
    843           }
    844           break;
    845 
    846       case CONTEXT_HUB_QUERY_APPS:
    847           rsp.result = 0;
    848           retVal = handle_query_apps_response(msg, msgLen, hubHandle);
    849           passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
    850           break;
    851 
    852       case CONTEXT_HUB_QUERY_MEMORY:
    853           // Deferring this use
    854           retVal = 0;
    855           break;
    856 
    857       case CONTEXT_HUB_OS_REBOOT:
    858           if (isValidOsStatus(msg, msgLen, &rsp)) {
    859               rsp.result = 0;
    860               ALOGW("Context Hub handle %d restarted", hubHandle);
    861               closeTxn();
    862               passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
    863               query_hub_for_apps(hubHandle);
    864               retVal = 0;
    865           }
    866           break;
    867 
    868       default:
    869           retVal = -1;
    870           break;
    871     }
    872 
    873     return retVal;
    874 }
    875 
    876 static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
    877     int *ptr = (int *)cookie;
    878 
    879     if (!ptr || *ptr >= db.hubInfo.numHubs) {
    880         return false;
    881     }
    882 
    883     if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
    884         return false;
    885     } else {
    886         return true;
    887     }
    888 }
    889 
    890 
    891 int context_hub_callback(uint32_t hubId,
    892                          const struct hub_message_t *msg,
    893                          void *cookie) {
    894     if (!msg) {
    895         ALOGW("NULL message");
    896         return -1;
    897     }
    898     if (!sanity_check_cookie(cookie, hubId)) {
    899         ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
    900               hubId, cookie);
    901 
    902         return -1;
    903     }
    904 
    905 
    906     uint32_t messageType = msg->message_type;
    907     uint32_t hubHandle = *(uint32_t*) cookie;
    908 
    909     if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
    910         handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
    911     } else {
    912         jint appHandle = get_app_instance_for_app_id(msg->app_name.id);
    913         if (appHandle < 0) {
    914             ALOGE("Filtering out message due to invalid App Instance.");
    915         } else {
    916             uint32_t msgHeader[MSG_HEADER_SIZE] = {};
    917             msgHeader[HEADER_FIELD_MSG_TYPE] = messageType;
    918             msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
    919             msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle;
    920             onMessageReceipt(msgHeader, MSG_HEADER_SIZE, (char*) msg->message, msg->message_len);
    921         }
    922     }
    923 
    924     return 0;
    925 }
    926 
    927 static int init_jni(JNIEnv *env, jobject instance) {
    928 
    929     if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
    930         return -1;
    931     }
    932 
    933     db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
    934 
    935     db.jniInfo.contextHubInfoClass =
    936             env->FindClass("android/hardware/location/ContextHubInfo");
    937 
    938     db.jniInfo.contextHubServiceClass =
    939             env->FindClass("android/hardware/location/ContextHubService");
    940 
    941     db.jniInfo.memoryRegionsClass =
    942             env->FindClass("android/hardware/location/MemoryRegion");
    943 
    944     db.jniInfo.contextHubInfoCtor =
    945             env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
    946     db.jniInfo.contextHubInfoSetId =
    947             env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
    948     db.jniInfo.contextHubInfoSetName =
    949             env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
    950                                 "(Ljava/lang/String;)V");
    951 
    952     db.jniInfo.contextHubInfoSetVendor =
    953             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    954                                 "setVendor", "(Ljava/lang/String;)V");
    955     db.jniInfo.contextHubInfoSetToolchain =
    956             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    957                                 "setToolchain", "(Ljava/lang/String;)V");
    958     db.jniInfo.contextHubInfoSetPlatformVersion =
    959             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    960                                 "setPlatformVersion", "(I)V");
    961     db.jniInfo.contextHubInfoSetStaticSwVersion =
    962             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    963                                 "setStaticSwVersion", "(I)V");
    964     db.jniInfo.contextHubInfoSetToolchainVersion =
    965             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    966                                 "setToolchainVersion", "(I)V");
    967     db.jniInfo.contextHubInfoSetPeakMips =
    968             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    969                                 "setPeakMips", "(F)V");
    970     db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
    971             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    972                                 "setStoppedPowerDrawMw", "(F)V");
    973     db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
    974             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    975                                 "setSleepPowerDrawMw", "(F)V");
    976     db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
    977             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    978                                 "setPeakPowerDrawMw", "(F)V");
    979     db.jniInfo.contextHubInfoSetSupportedSensors =
    980             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    981                                 "setSupportedSensors", "([I)V");
    982     db.jniInfo.contextHubInfoSetMemoryRegions =
    983             env->GetMethodID(db.jniInfo.contextHubInfoClass,
    984                                 "setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
    985     db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
    986              env->GetMethodID(db.jniInfo.contextHubInfoClass,
    987                                 "setMaxPacketLenBytes", "(I)V");
    988 
    989 
    990     db.jniInfo.contextHubServiceMsgReceiptCallback =
    991             env->GetMethodID(db.jniInfo.contextHubServiceClass, "onMessageReceipt",
    992                                "([I[B)I");
    993     db.jniInfo.contextHubInfoSetName =
    994             env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
    995             "(Ljava/lang/String;)V");
    996 
    997     db.jniInfo.contextHubServiceAddAppInstance =
    998                  env->GetMethodID(db.jniInfo.contextHubServiceClass,
    999                                     "addAppInstance", "(IIJI)I");
   1000 
   1001     db.jniInfo.contextHubServiceDeleteAppInstance =
   1002                  env->GetMethodID(db.jniInfo.contextHubServiceClass,
   1003                                     "deleteAppInstance", "(I)I");
   1004 
   1005     return 0;
   1006 }
   1007 
   1008 static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t *hub) {
   1009     jstring jstrBuf;
   1010     jintArray jintBuf;
   1011     jobjectArray jmemBuf;
   1012 
   1013     jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
   1014                                   db.jniInfo.contextHubInfoCtor);
   1015     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
   1016 
   1017     jstrBuf = env->NewStringUTF(hub->name);
   1018     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
   1019     env->DeleteLocalRef(jstrBuf);
   1020 
   1021     jstrBuf = env->NewStringUTF(hub->vendor);
   1022     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
   1023     env->DeleteLocalRef(jstrBuf);
   1024 
   1025     jstrBuf = env->NewStringUTF(hub->toolchain);
   1026     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
   1027     env->DeleteLocalRef(jstrBuf);
   1028 
   1029     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
   1030     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
   1031     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
   1032     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
   1033                         hub->stopped_power_draw_mw);
   1034     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
   1035                         hub->sleep_power_draw_mw);
   1036     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
   1037                         hub->peak_power_draw_mw);
   1038     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
   1039                         hub->max_supported_msg_len);
   1040 
   1041 
   1042     jintBuf = env->NewIntArray(hub->num_connected_sensors);
   1043     int *connectedSensors = new int[hub->num_connected_sensors];
   1044 
   1045     if (!connectedSensors) {
   1046       ALOGW("Cannot allocate memory! Unexpected");
   1047       assert(false);
   1048     } else {
   1049       for (unsigned int i = 0; i < hub->num_connected_sensors; i++) {
   1050         connectedSensors[i] = hub->connected_sensors[i].sensor_id;
   1051       }
   1052     }
   1053 
   1054     env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
   1055                            connectedSensors);
   1056 
   1057     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
   1058     env->DeleteLocalRef(jintBuf);
   1059 
   1060     // We are not getting the memory regions from the CH Hal - change this when it is available
   1061     jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
   1062     // Note the zero size above. We do not need to set any elements
   1063     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
   1064     env->DeleteLocalRef(jmemBuf);
   1065 
   1066 
   1067     delete[] connectedSensors;
   1068     return jHub;
   1069 }
   1070 
   1071 static jobjectArray nativeInitialize(JNIEnv *env, jobject instance)
   1072 {
   1073     jobject hub;
   1074     jobjectArray retArray;
   1075 
   1076     if (init_jni(env, instance) < 0) {
   1077         return nullptr;
   1078     }
   1079 
   1080     initContextHubService();
   1081 
   1082     if (db.hubInfo.numHubs > 1) {
   1083       ALOGW("Clamping the number of hubs to 1");
   1084       db.hubInfo.numHubs = 1;
   1085     }
   1086 
   1087     retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
   1088 
   1089     for(int i = 0; i < db.hubInfo.numHubs; i++) {
   1090         hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
   1091         env->SetObjectArrayElement(retArray, i, hub);
   1092     }
   1093 
   1094     return retArray;
   1095 }
   1096 
   1097 static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
   1098                               jbyteArray data_) {
   1099     jint retVal = -1; // Default to failure
   1100 
   1101     jint *header = env->GetIntArrayElements(header_, 0);
   1102     unsigned int numHeaderElements = env->GetArrayLength(header_);
   1103     jbyte *data = env->GetByteArrayElements(data_, 0);
   1104     int dataBufferLength = env->GetArrayLength(data_);
   1105 
   1106     if (numHeaderElements < MSG_HEADER_SIZE) {
   1107         ALOGW("Malformed header len");
   1108         return -1;
   1109     }
   1110 
   1111     uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
   1112     uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
   1113     int hubHandle = -1;
   1114     int hubId;
   1115     uint64_t appId;
   1116 
   1117     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1118         hubHandle = get_hub_handle_for_app_instance(appInstanceHandle);
   1119     } else if (msgType == CONTEXT_HUB_LOAD_APP) {
   1120         if (numHeaderElements < MSG_HEADER_SIZE_LOAD_APP) {
   1121             return -1;
   1122         }
   1123         uint64_t appIdLo = header[HEADER_FIELD_LOAD_APP_ID_LO];
   1124         uint64_t appIdHi = header[HEADER_FIELD_LOAD_APP_ID_HI];
   1125         appId = appIdHi << 32 | appIdLo;
   1126 
   1127         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
   1128     } else {
   1129         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
   1130     }
   1131 
   1132     if (hubHandle < 0) {
   1133         ALOGD("Invalid hub Handle %d", hubHandle);
   1134         return -1;
   1135     }
   1136 
   1137     if (msgType == CONTEXT_HUB_LOAD_APP ||
   1138         msgType == CONTEXT_HUB_UNLOAD_APP) {
   1139 
   1140         if (isTxnPending()) {
   1141             ALOGW("Cannot load or unload app while a transaction is pending !");
   1142             return -1;
   1143         }
   1144 
   1145         if (msgType == CONTEXT_HUB_LOAD_APP) {
   1146             if (startLoadAppTxn(appId, hubHandle) != 0) {
   1147                 ALOGW("Cannot Start Load Transaction");
   1148                 return -1;
   1149             }
   1150         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1151             if (startUnloadAppTxn(appInstanceHandle) != 0) {
   1152                 ALOGW("Cannot Start UnLoad Transaction");
   1153                 return -1;
   1154             }
   1155         }
   1156     }
   1157 
   1158     bool setAddressSuccess = false;
   1159     hub_message_t msg;
   1160 
   1161     msg.message_type = msgType;
   1162 
   1163     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1164         msg.message_len = sizeof(db.appInstances[appInstanceHandle].appInfo.app_name);
   1165         msg.message = &db.appInstances[appInstanceHandle].appInfo.app_name;
   1166         setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
   1167         hubId = get_hub_id_for_hub_handle(hubHandle);
   1168     } else {
   1169         msg.message_len = dataBufferLength;
   1170         msg.message = data;
   1171 
   1172         if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
   1173             setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
   1174             hubId = get_hub_id_for_hub_handle(hubHandle);
   1175         } else {
   1176             setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
   1177             hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
   1178         }
   1179     }
   1180 
   1181     if (setAddressSuccess && hubId >= 0) {
   1182         ALOGD("Asking HAL to remove app");
   1183         retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
   1184     } else {
   1185       ALOGD("Could not find app instance %" PRId32 " on hubHandle %" PRId32
   1186             ", setAddress %d",
   1187             header[HEADER_FIELD_APP_INSTANCE],
   1188             header[HEADER_FIELD_HUB_HANDLE],
   1189             (int)setAddressSuccess);
   1190     }
   1191 
   1192     if (retVal != 0) {
   1193         ALOGD("Send Message failure - %d", retVal);
   1194         if (msgType == CONTEXT_HUB_LOAD_APP) {
   1195             jint ignored;
   1196             closeLoadTxn(false, &ignored);
   1197         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
   1198             closeUnloadTxn(false);
   1199         }
   1200     }
   1201 
   1202     env->ReleaseIntArrayElements(header_, header, 0);
   1203     env->ReleaseByteArrayElements(data_, data, 0);
   1204 
   1205     return retVal;
   1206 }
   1207 
   1208 //--------------------------------------------------------------------------------------------------
   1209 //
   1210 static const JNINativeMethod gContextHubServiceMethods[] = {
   1211     {"nativeInitialize",
   1212              "()[Landroid/hardware/location/ContextHubInfo;",
   1213              (void*)nativeInitialize },
   1214     {"nativeSendMessage",
   1215             "([I[B)I",
   1216             (void*)nativeSendMessage }
   1217 };
   1218 
   1219 }//namespace android
   1220 
   1221 using namespace android;
   1222 
   1223 int register_android_hardware_location_ContextHubService(JNIEnv *env)
   1224 {
   1225     RegisterMethodsOrDie(env, "android/hardware/location/ContextHubService",
   1226             gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
   1227 
   1228     return 0;
   1229 }
   1230