• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
TxnManager()162     TxnManager() {
163         mData = nullptr;
164         mIsPending = false;
165     }
166 
~TxnManager()167     ~TxnManager() {
168         closeTxn();
169     }
170 
addTxn(HubMessageType txnIdentifier,void * txnData)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 
closeTxn()185     int closeTxn() {
186         std::lock_guard<std::mutex>lock(mLock);
187         closeTxnUnlocked();
188         return 0;
189     }
190 
isTxnPending()191     bool isTxnPending() {
192         std::lock_guard<std::mutex>lock(mLock);
193         return mIsPending;
194     }
195 
closeAnyStaleTxns()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 
fetchTxnData(HubMessageType * id,void ** data)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.
closeTxnUnlocked()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 
ContextHubServiceCallbackandroid::ContextHubServiceCallback242     ContextHubServiceCallback(uint32_t hubId) {
243         mContextHubId = hubId;
244     }
245 
handleClientMsgandroid::ContextHubServiceCallback246     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 
handleHubEventandroid::ContextHubServiceCallback264     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 
handleTxnResultandroid::ContextHubServiceCallback275     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 
handleAppsInfoandroid::ContextHubServiceCallback332     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 
handleAppAbortandroid::ContextHubServiceCallback340     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 
setContextHubIdandroid::ContextHubServiceCallback349     void setContextHubId(uint32_t id) {
350         mContextHubId = id;
351     }
352 
getContextHubIdandroid::ContextHubServiceCallback353     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 
getHubIdForHubHandle(int hubHandle,uint32_t * hubId)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 
getHubHandleForAppInstance(jint id)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 
getAppInstanceForAppId(uint64_t app_id)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 
getAppIdForAppInstance(jint id)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 
queryHubForApps(uint32_t hubId)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 
sendQueryForApps()426 void sendQueryForApps() {
427     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
428         queryHubForApps(db.hubInfo.hubs[i].hubId);
429     }
430 }
431 
returnId(jint id)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 
generateId()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 
addAppInstance(const HubAppInfo * appInfo,uint32_t hubHandle,jint appInstanceHandle,JNIEnv * env)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 
deleteAppInstance(jint id,JNIEnv * env)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 
startLoadAppTxn(uint64_t appId,int hubHandle)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         delete 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         delete txnInfo;
530         return -1;
531     }
532 
533     return 0;
534 }
535 
startUnloadAppTxn(jint appInstanceHandle)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         delete txnData;
547         ALOGW("Cannot start transaction to unload app");
548         return -1;
549     }
550 
551     return 0;
552 }
553 
getHubsCb(const::android::hardware::hidl_vec<ContextHub> & hubs)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 
initContextHubService()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 
onHubReset(uint32_t hubId)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 
onMessageReceipt(const uint32_t * header,size_t headerLen,const char * msg,size_t msgLen)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 
handleQueryAppsResponse(const std::vector<HubAppInfo> apps,uint32_t hubHandle)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.
passOnOsResponse(uint32_t hubHandle,uint32_t msgType,TransactionResult result,const int8_t * additionalData,size_t additionalDataLen)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 
closeUnloadTxn(bool success)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 
closeLoadTxn(bool success,jint * appInstanceHandle)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 
initJni(JNIEnv * env,jobject instance)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 
constructJContextHubInfo(JNIEnv * env,const ContextHub & hub)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 
nativeInitialize(JNIEnv * env,jobject instance)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 
sendLoadNanoAppRequest(uint32_t hubId,jbyte * data,size_t dataBufferLength)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 
nativeSendMessage(JNIEnv * env,jobject instance,jintArray header_,jbyteArray data_)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 
register_android_server_location_ContextHubService(JNIEnv * env)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