2 * Copyright 2016, The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "context_hub.h"
20 #define LOG_TAG "ContextHubService"
29 #include <unordered_map>
32 #include <cutils/log.h>
35 #include "core_jni_helpers.h"
37 static constexpr int OS_APP_ID = -1;
38 static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
40 static constexpr int MIN_APP_ID = 1;
41 static constexpr int MAX_APP_ID = 128;
43 static constexpr size_t MSG_HEADER_SIZE = 4;
44 static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
45 static constexpr size_t HEADER_FIELD_MSG_VERSION = 1;
46 static constexpr size_t HEADER_FIELD_HUB_HANDLE = 2;
47 static constexpr size_t HEADER_FIELD_APP_INSTANCE = 3;
49 static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
50 static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
51 static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
58 * Finds the length of a statically-sized array using template trickery that
59 * also prevents it from being applied to the wrong type.
61 template <typename T, size_t N>
62 constexpr size_t array_length(T (&)[N]) { return N; }
66 jclass contextHubInfoClass;
67 jclass contextHubServiceClass;
68 jclass memoryRegionsClass;
70 jobject jContextHubService;
72 jmethodID msgReceiptCallBack;
74 jmethodID contextHubInfoCtor;
75 jmethodID contextHubInfoSetId;
76 jmethodID contextHubInfoSetName;
77 jmethodID contextHubInfoSetVendor;
78 jmethodID contextHubInfoSetToolchain;
79 jmethodID contextHubInfoSetPlatformVersion;
80 jmethodID contextHubInfoSetStaticSwVersion;
81 jmethodID contextHubInfoSetToolchainVersion;
82 jmethodID contextHubInfoSetPeakMips;
83 jmethodID contextHubInfoSetStoppedPowerDrawMw;
84 jmethodID contextHubInfoSetSleepPowerDrawMw;
85 jmethodID contextHubInfoSetPeakPowerDrawMw;
86 jmethodID contextHubInfoSetSupportedSensors;
87 jmethodID contextHubInfoSetMemoryRegions;
88 jmethodID contextHubInfoSetMaxPacketLenBytes;
90 jmethodID contextHubServiceMsgReceiptCallback;
91 jmethodID contextHubServiceAddAppInstance;
92 jmethodID contextHubServiceDeleteAppInstance;
95 struct context_hub_info_s {
98 const struct context_hub_t *hubs;
99 struct context_hub_module_t *contextHubModule;
102 struct app_instance_info_s {
103 uint64_t truncName; // Possibly truncated name for logging
104 uint32_t hubHandle; // Id of the hub this app is on
105 int instanceId; // system wide unique instance id - assigned
106 struct hub_app_info appInfo; // returned from the HAL
110 * TODO(ashutoshj): From original code review:
112 * So, I feel like we could possible do a better job of organizing this code,
113 * and being more C++-y. Consider something like this:
118 * int add(hub_message_e identifier, void *data);
120 * bool isPending() const;
121 * int fetchData(hub_message_e *identifier, void **data) const;
125 * mutable std::mutex mLock;
126 * hub_message_e mIdentifier;
130 * And then, for example, we'd have things like:
131 * TxnManager::TxnManager() : mPending(false), mLock(), mIdentifier(), mData(nullptr) {}
132 * int TxnManager::add(hub_message_e identifier, void *data) {
133 * std::lock_guard<std::mutex> lock(mLock);
136 * mIdentifier = txnIdentifier;
139 * And then calling code would look like:
140 * if (!db.txnManager.add(CONTEXT_HUB_LOAD_APP, txnInfo)) {
142 * This would make it clearer the nothing is manipulating any state within TxnManager
143 * unsafely and outside of these couple of calls.
145 struct txnManager_s {
146 bool txnPending; // Is a transaction pending
147 std::mutex m; // mutex for manager
148 hub_messages_e txnIdentifier; // What are we doing
149 void *txnData; // Details
152 struct contextHubServiceDb_s {
154 context_hub_info_s hubInfo;
156 std::queue<int> freeIds;
157 std::unordered_map<int, app_instance_info_s> appInstances;
158 txnManager_s txnManager;
161 } // unnamed namespace
163 static contextHubServiceDb_s db;
165 static bool initTxnManager() {
166 txnManager_s *mgr = &db.txnManager;
168 mgr->txnData = nullptr;
169 mgr->txnPending = false;
173 static int addTxn(hub_messages_e txnIdentifier, void *txnData) {
174 txnManager_s *mgr = &db.txnManager;
176 std::lock_guard<std::mutex>lock(mgr->m);
178 mgr->txnPending = true;
179 mgr->txnData = txnData;
180 mgr->txnIdentifier = txnIdentifier;
185 static int closeTxn() {
186 txnManager_s *mgr = &db.txnManager;
187 std::lock_guard<std::mutex>lock(mgr->m);
188 mgr->txnPending = false;
190 mgr->txnData = nullptr;
195 static bool isTxnPending() {
196 txnManager_s *mgr = &db.txnManager;
197 std::lock_guard<std::mutex>lock(mgr->m);
198 return mgr->txnPending;
201 static int fetchTxnData(hub_messages_e *id, void **data) {
202 txnManager_s *mgr = &db.txnManager;
205 ALOGW("Null params id %p, data %p", id, data);
209 std::lock_guard<std::mutex>lock(mgr->m);
210 if (!mgr->txnPending) {
211 ALOGW("No Transactions pending");
216 *id = mgr->txnIdentifier;
217 *data = mgr->txnData;
221 int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
224 const context_hub_t *get_hub_info(int hubHandle) {
225 if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
226 return &db.hubInfo.hubs[hubHandle];
231 static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
232 const context_hub_t *info = get_hub_info(hubHandle);
235 return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
237 ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
242 static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
243 const context_hub_t *info = get_hub_info(hubHandle);
246 msg->app_name = info->os_app_name;
249 ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
254 static int get_hub_id_for_hub_handle(int hubHandle) {
255 if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
258 return db.hubInfo.hubs[hubHandle].hub_id;
262 static int get_hub_handle_for_app_instance(int id) {
263 if (!db.appInstances.count(id)) {
264 ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
268 return db.appInstances[id].hubHandle;
271 static int get_hub_id_for_app_instance(int id) {
272 int hubHandle = get_hub_handle_for_app_instance(id);
278 return db.hubInfo.hubs[hubHandle].hub_id;
281 static int get_app_instance_for_app_id(uint64_t app_id) {
282 auto end = db.appInstances.end();
283 for (auto current = db.appInstances.begin(); current != end; ++current) {
284 if (current->second.appInfo.app_name.id == app_id) {
285 return current->first;
288 ALOGD("Cannot find app for app instance %" PRIu64 ".", app_id);
292 static int set_dest_app(hub_message_t *msg, int id) {
293 if (!db.appInstances.count(id)) {
294 ALOGD("%s: Cannot find app for app instance %d", __FUNCTION__, id);
298 msg->app_name = db.appInstances[id].appInfo.app_name;
302 static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
304 query_apps_request_t queryMsg;
306 queryMsg.app_name.id = NANOAPP_VENDOR_ALL_APPS;
308 msg.message_type = CONTEXT_HUB_QUERY_APPS;
309 msg.message_len = sizeof(queryMsg);
310 msg.message = &queryMsg;
312 ALOGD("Sending query for apps to hub %" PRIu32, hubHandle);
313 set_os_app_as_destination(&msg, hubHandle);
314 if (send_msg_to_hub(&msg, hubHandle) != 0) {
315 ALOGW("Could not query hub %" PRIu32 " for apps", hubHandle);
319 static void sendQueryForApps(uint64_t appId) {
320 for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
321 query_hub_for_apps(appId, i);
325 static int return_id(int id) {
326 // Note : This method is not thread safe.
327 // id returned is guaranteed to be in use
336 static int generate_id() {
337 // Note : This method is not thread safe.
340 if (!db.freeIds.empty()) {
341 retVal = db.freeIds.front();
349 static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
350 int appInstanceHandle, JNIEnv *env) {
352 ALOGI("Loading App");
354 // Not checking if the apps are indeed distinct
355 app_instance_info_s entry;
358 if (db.appInstances.count(appInstanceHandle) == 0) {
359 appInstanceHandle = generate_id();
360 if (appInstanceHandle < 0) {
361 ALOGE("Cannot find resources to add app instance %d",
367 entry.appInfo = *appInfo;
369 entry.instanceId = appInstanceHandle;
370 entry.truncName = appInfo->app_name.id;
371 entry.hubHandle = hubHandle;
373 db.appInstances[appInstanceHandle] = entry;
375 // Finally - let the service know of this app instance
376 env->CallIntMethod(db.jniInfo.jContextHubService,
377 db.jniInfo.contextHubServiceAddAppInstance,
378 hubHandle, entry.instanceId, entry.truncName,
379 entry.appInfo.version);
381 ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
382 " as appInstance %d", entry.truncName,
383 entry.hubHandle, appInstanceHandle);
385 return appInstanceHandle;
388 int delete_app_instance(int id, JNIEnv *env) {
389 if (!db.appInstances.count(id)) {
390 ALOGW("Cannot find App id : %d", id);
395 db.appInstances.erase(id);
396 if (env->CallIntMethod(db.jniInfo.jContextHubService,
397 db.jniInfo.contextHubServiceDeleteAppInstance,
399 ALOGW("Could not delete App id : %d", id);
403 ALOGI("Deleted App id : %d", id);
408 static int startLoadAppTxn(uint64_t appId, int hubHandle) {
409 app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
410 int instanceId = generate_id();
412 if (!txnInfo || instanceId < 0) {
413 return_id(instanceId);
418 txnInfo->truncName = appId;
419 txnInfo->hubHandle = hubHandle;
420 txnInfo->instanceId = instanceId;
422 txnInfo->appInfo.app_name.id = appId;
423 txnInfo->appInfo.num_mem_ranges = 0;
424 txnInfo->appInfo.version = -1; // Awaited
426 if (addTxn(CONTEXT_HUB_LOAD_APP, txnInfo) != 0) {
427 return_id(instanceId);
435 static int startUnloadAppTxn(uint32_t appInstanceHandle) {
436 uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t));
438 ALOGW("Cannot allocate memory to start unload transaction");
442 *txnData = appInstanceHandle;
444 if (addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) {
446 ALOGW("Cannot start transaction to unload app");
453 static void initContextHubService() {
455 db.hubInfo.hubs = nullptr;
456 db.hubInfo.numHubs = 0;
459 err = hw_get_module(CONTEXT_HUB_MODULE_ID,
460 (hw_module_t const**)(&db.hubInfo.contextHubModule));
463 ALOGE("** Could not load %s module : err %s", CONTEXT_HUB_MODULE_ID,
467 // Prep for storing app info
468 for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
473 if (db.hubInfo.contextHubModule) {
474 int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
476 ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
477 db.hubInfo.numHubs = retNumHubs;
479 if (db.hubInfo.numHubs > 0) {
480 db.hubInfo.numHubs = retNumHubs;
481 db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
483 if (!db.hubInfo.cookies) {
484 ALOGW("Ran out of memory allocating cookies, bailing");
488 for (i = 0; i < db.hubInfo.numHubs; i++) {
489 db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
490 ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
491 if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
492 context_hub_callback,
493 &db.hubInfo.cookies[i]) == 0) {
498 sendQueryForApps(ALL_APPS);
500 ALOGW("No Context Hub Module present");
504 static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_t msgLen) {
507 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
511 jbyteArray jmsg = env->NewByteArray(msgLen);
512 if (jmsg == nullptr) {
513 ALOGW("Can't allocate %zu byte array", msgLen);
516 jintArray jheader = env->NewIntArray(headerLen);
517 if (jheader == nullptr) {
518 env->DeleteLocalRef(jmsg);
519 ALOGW("Can't allocate %zu int array", headerLen);
523 env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
524 env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
526 int ret = (env->CallIntMethod(db.jniInfo.jContextHubService,
527 db.jniInfo.contextHubServiceMsgReceiptCallback,
528 jheader, jmsg) != 0);
529 env->DeleteLocalRef(jmsg);
530 env->DeleteLocalRef(jheader);
535 int handle_query_apps_response(const uint8_t *msg, int msgLen,
536 uint32_t hubHandle) {
538 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
542 int numApps = msgLen/sizeof(hub_app_info);
544 const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
546 for (int i = 0; i < numApps; i++, unalignedInfoAddr++) {
547 memcpy(&info, unalignedInfoAddr, sizeof(info));
548 // We will only have one instance of the app
549 // TODO : Change this logic once we support multiple instances of the same app
550 int appInstance = get_app_instance_for_app_id(info.app_name.id);
551 add_app_instance(&info, hubHandle, appInstance, env);
557 static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
558 status_response_t *rsp, int8_t *additionalData,
559 size_t additionalDataLen) {
562 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
563 ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32, msgType);
567 uint32_t header[MSG_HEADER_SIZE];
568 memset(header, 0, sizeof(header));
570 if (!additionalData) {
571 additionalDataLen = 0; // clamp
573 int msgLen = 1 + additionalDataLen;
575 int8_t *msg = new int8_t[msgLen];
578 ALOGW("Unexpected : Ran out of memory, cannot send response");
582 header[HEADER_FIELD_MSG_TYPE] = msgType;
583 header[HEADER_FIELD_MSG_VERSION] = 0;
584 header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
585 header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
587 msg[0] = rsp->result;
589 if (additionalData) {
590 memcpy(&msg[1], additionalData, additionalDataLen);
593 jbyteArray jmsg = env->NewByteArray(msgLen);
594 jintArray jheader = env->NewIntArray(sizeof(header));
596 env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
597 env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
599 ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
600 header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE],
601 header[HEADER_FIELD_HUB_HANDLE]);
603 env->CallIntMethod(db.jniInfo.jContextHubService,
604 db.jniInfo.contextHubServiceMsgReceiptCallback,
610 void closeUnloadTxn(bool success) {
611 void *txnData = nullptr;
612 hub_messages_e txnId;
614 if (success && fetchTxnData(&txnId, &txnData) == 0 &&
615 txnId == CONTEXT_HUB_UNLOAD_APP) {
616 db.appInstances.erase(*(uint32_t *)txnData);
618 ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
624 void closeLoadTxn(bool success, int *appInstanceHandle) {
626 hub_messages_e txnId;
628 if (success && fetchTxnData(&txnId, &txnData) == 0 &&
629 txnId == CONTEXT_HUB_LOAD_APP) {
630 app_instance_info_s *info = (app_instance_info_s *)txnData;
631 *appInstanceHandle = info->instanceId;
634 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) {
635 add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
637 ALOGW("Could not attach to JVM !");
639 sendQueryForApps(info->appInfo.app_name.id);
641 ALOGW("Could not load the app successfully ! Unexpected failure");
647 static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
648 status_response_t *rsp) {
649 // Workaround a bug in some HALs
651 rsp->result = msg[0];
655 if (!msg || msgLen != sizeof(*rsp)) {
656 ALOGW("Received invalid response %p of size %zu", msg, msgLen);
660 memcpy(rsp, msg, sizeof(*rsp));
662 // No sanity checks on return values
666 static void invalidateNanoApps(uint32_t hubHandle) {
669 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
670 ALOGW("Could not attach to JVM !");
673 auto end = db.appInstances.end();
674 for (auto current = db.appInstances.begin(); current != end; ) {
675 app_instance_info_s info = current->second;
677 if (info.hubHandle == hubHandle) {
678 delete_app_instance(info.instanceId, env);
683 static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
684 const uint8_t *msg, int msgLen) {
687 ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d",
688 hubHandle, msgType, msgLen);
690 struct status_response_t rsp;
694 case CONTEXT_HUB_APPS_ENABLE:
695 case CONTEXT_HUB_APPS_DISABLE:
696 case CONTEXT_HUB_LOAD_APP:
697 case CONTEXT_HUB_UNLOAD_APP:
698 if (isValidOsStatus(msg, msgLen, &rsp)) {
699 if (msgType == CONTEXT_HUB_LOAD_APP) {
700 int appInstanceHandle;
701 closeLoadTxn(rsp.result == 0, &appInstanceHandle);
702 passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
703 sizeof(appInstanceHandle));
704 } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
705 closeUnloadTxn(rsp.result == 0);
706 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
708 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
714 case CONTEXT_HUB_QUERY_APPS:
716 retVal = handle_query_apps_response(msg, msgLen, hubHandle);
717 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
720 case CONTEXT_HUB_QUERY_MEMORY:
721 // Deferring this use
725 case CONTEXT_HUB_OS_REBOOT:
726 if (isValidOsStatus(msg, msgLen, &rsp)) {
728 ALOGW("Context Hub handle %d restarted", hubHandle);
730 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
731 invalidateNanoApps(hubHandle);
732 query_hub_for_apps(ALL_APPS, hubHandle);
745 static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
746 int *ptr = (int *)cookie;
748 if (!ptr || *ptr >= db.hubInfo.numHubs) {
752 if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
760 int context_hub_callback(uint32_t hubId,
761 const struct hub_message_t *msg,
764 ALOGW("NULL message");
767 if (!sanity_check_cookie(cookie, hubId)) {
768 ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
775 uint32_t messageType = msg->message_type;
776 uint32_t hubHandle = *(uint32_t*) cookie;
778 if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
779 handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
781 int appHandle = get_app_instance_for_app_id(msg->app_name.id);
783 ALOGE("Filtering out message due to invalid App Instance.");
785 uint32_t msgHeader[MSG_HEADER_SIZE] = {};
786 msgHeader[HEADER_FIELD_MSG_TYPE] = messageType;
787 msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
788 msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle;
789 onMessageReceipt(msgHeader, MSG_HEADER_SIZE, (char*) msg->message, msg->message_len);
796 static int init_jni(JNIEnv *env, jobject instance) {
798 if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
802 db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
804 db.jniInfo.contextHubInfoClass =
805 env->FindClass("android/hardware/location/ContextHubInfo");
807 db.jniInfo.contextHubServiceClass =
808 env->FindClass("android/hardware/location/ContextHubService");
810 db.jniInfo.memoryRegionsClass =
811 env->FindClass("android/hardware/location/MemoryRegion");
813 db.jniInfo.contextHubInfoCtor =
814 env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
815 db.jniInfo.contextHubInfoSetId =
816 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
817 db.jniInfo.contextHubInfoSetName =
818 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
819 "(Ljava/lang/String;)V");
821 db.jniInfo.contextHubInfoSetVendor =
822 env->GetMethodID(db.jniInfo.contextHubInfoClass,
823 "setVendor", "(Ljava/lang/String;)V");
824 db.jniInfo.contextHubInfoSetToolchain =
825 env->GetMethodID(db.jniInfo.contextHubInfoClass,
826 "setToolchain", "(Ljava/lang/String;)V");
827 db.jniInfo.contextHubInfoSetPlatformVersion =
828 env->GetMethodID(db.jniInfo.contextHubInfoClass,
829 "setPlatformVersion", "(I)V");
830 db.jniInfo.contextHubInfoSetStaticSwVersion =
831 env->GetMethodID(db.jniInfo.contextHubInfoClass,
832 "setStaticSwVersion", "(I)V");
833 db.jniInfo.contextHubInfoSetToolchainVersion =
834 env->GetMethodID(db.jniInfo.contextHubInfoClass,
835 "setToolchainVersion", "(I)V");
836 db.jniInfo.contextHubInfoSetPeakMips =
837 env->GetMethodID(db.jniInfo.contextHubInfoClass,
838 "setPeakMips", "(F)V");
839 db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
840 env->GetMethodID(db.jniInfo.contextHubInfoClass,
841 "setStoppedPowerDrawMw", "(F)V");
842 db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
843 env->GetMethodID(db.jniInfo.contextHubInfoClass,
844 "setSleepPowerDrawMw", "(F)V");
845 db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
846 env->GetMethodID(db.jniInfo.contextHubInfoClass,
847 "setPeakPowerDrawMw", "(F)V");
848 db.jniInfo.contextHubInfoSetSupportedSensors =
849 env->GetMethodID(db.jniInfo.contextHubInfoClass,
850 "setSupportedSensors", "([I)V");
851 db.jniInfo.contextHubInfoSetMemoryRegions =
852 env->GetMethodID(db.jniInfo.contextHubInfoClass,
853 "setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
854 db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
855 env->GetMethodID(db.jniInfo.contextHubInfoClass,
856 "setMaxPacketLenBytes", "(I)V");
859 db.jniInfo.contextHubServiceMsgReceiptCallback =
860 env->GetMethodID(db.jniInfo.contextHubServiceClass, "onMessageReceipt",
862 db.jniInfo.contextHubInfoSetName =
863 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
864 "(Ljava/lang/String;)V");
866 db.jniInfo.contextHubServiceAddAppInstance =
867 env->GetMethodID(db.jniInfo.contextHubServiceClass,
868 "addAppInstance", "(IIJI)I");
870 db.jniInfo.contextHubServiceDeleteAppInstance =
871 env->GetMethodID(db.jniInfo.contextHubServiceClass,
872 "deleteAppInstance", "(I)I");
877 static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t *hub) {
880 jobjectArray jmemBuf;
882 jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
883 db.jniInfo.contextHubInfoCtor);
884 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
886 jstrBuf = env->NewStringUTF(hub->name);
887 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
888 env->DeleteLocalRef(jstrBuf);
890 jstrBuf = env->NewStringUTF(hub->vendor);
891 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
892 env->DeleteLocalRef(jstrBuf);
894 jstrBuf = env->NewStringUTF(hub->toolchain);
895 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
896 env->DeleteLocalRef(jstrBuf);
898 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
899 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
900 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
901 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
902 hub->stopped_power_draw_mw);
903 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
904 hub->sleep_power_draw_mw);
905 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
906 hub->peak_power_draw_mw);
907 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
908 hub->max_supported_msg_len);
911 jintBuf = env->NewIntArray(hub->num_connected_sensors);
912 int *connectedSensors = new int[hub->num_connected_sensors];
914 if (!connectedSensors) {
915 ALOGW("Cannot allocate memory! Unexpected");
918 for (unsigned int i = 0; i < hub->num_connected_sensors; i++) {
919 connectedSensors[i] = hub->connected_sensors[i].sensor_id;
923 env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
926 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
927 env->DeleteLocalRef(jintBuf);
929 // We are not getting the memory regions from the CH Hal - change this when it is available
930 jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
931 // Note the zero size above. We do not need to set any elements
932 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
933 env->DeleteLocalRef(jmemBuf);
936 delete[] connectedSensors;
940 static jobjectArray nativeInitialize(JNIEnv *env, jobject instance)
943 jobjectArray retArray;
945 if (init_jni(env, instance) < 0) {
949 initContextHubService();
951 if (db.hubInfo.numHubs > 1) {
952 ALOGW("Clamping the number of hubs to 1");
953 db.hubInfo.numHubs = 1;
956 retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
958 for(int i = 0; i < db.hubInfo.numHubs; i++) {
959 hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
960 env->SetObjectArrayElement(retArray, i, hub);
966 static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
968 jint retVal = -1; // Default to failure
970 jint *header = env->GetIntArrayElements(header_, 0);
971 unsigned int numHeaderElements = env->GetArrayLength(header_);
972 jbyte *data = env->GetByteArrayElements(data_, 0);
973 int dataBufferLength = env->GetArrayLength(data_);
975 if (numHeaderElements < MSG_HEADER_SIZE) {
976 ALOGW("Malformed header len");
980 uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
981 uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
986 if (msgType == CONTEXT_HUB_UNLOAD_APP) {
987 hubHandle = get_hub_handle_for_app_instance(appInstanceHandle);
988 } else if (msgType == CONTEXT_HUB_LOAD_APP) {
989 if (numHeaderElements < MSG_HEADER_SIZE_LOAD_APP) {
992 uint64_t appIdLo = header[HEADER_FIELD_LOAD_APP_ID_LO];
993 uint64_t appIdHi = header[HEADER_FIELD_LOAD_APP_ID_HI];
994 appId = appIdHi << 32 | appIdLo;
996 hubHandle = header[HEADER_FIELD_HUB_HANDLE];
998 hubHandle = header[HEADER_FIELD_HUB_HANDLE];
1001 if (hubHandle < 0) {
1002 ALOGD("Invalid hub Handle %d", hubHandle);
1006 if (msgType == CONTEXT_HUB_LOAD_APP ||
1007 msgType == CONTEXT_HUB_UNLOAD_APP) {
1009 if (isTxnPending()) {
1010 ALOGW("Cannot load or unload app while a transaction is pending !");
1014 if (msgType == CONTEXT_HUB_LOAD_APP) {
1015 if (startLoadAppTxn(appId, hubHandle) != 0) {
1016 ALOGW("Cannot Start Load Transaction");
1019 } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1020 if (startUnloadAppTxn(appInstanceHandle) != 0) {
1021 ALOGW("Cannot Start UnLoad Transaction");
1027 bool setAddressSuccess = false;
1030 msg.message_type = msgType;
1032 if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1033 msg.message_len = sizeof(db.appInstances[appInstanceHandle].appInfo.app_name);
1034 msg.message = &db.appInstances[appInstanceHandle].appInfo.app_name;
1035 setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
1036 hubId = get_hub_id_for_hub_handle(hubHandle);
1038 msg.message_len = dataBufferLength;
1041 if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
1042 setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
1043 hubId = get_hub_id_for_hub_handle(hubHandle);
1045 setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
1046 hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
1050 if (setAddressSuccess && hubId >= 0) {
1051 ALOGD("Asking HAL to remove app");
1052 retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
1054 ALOGD("Could not find app instance %d on hubHandle %d, setAddress %d",
1055 header[HEADER_FIELD_APP_INSTANCE],
1056 header[HEADER_FIELD_HUB_HANDLE],
1057 (int)setAddressSuccess);
1061 ALOGD("Send Message failure - %d", retVal);
1062 if (msgType == CONTEXT_HUB_LOAD_APP) {
1063 closeLoadTxn(false, nullptr);
1064 } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1065 closeUnloadTxn(false);
1069 env->ReleaseIntArrayElements(header_, header, 0);
1070 env->ReleaseByteArrayElements(data_, data, 0);
1075 //--------------------------------------------------------------------------------------------------
1077 static const JNINativeMethod gContextHubServiceMethods[] = {
1078 {"nativeInitialize",
1079 "()[Landroid/hardware/location/ContextHubInfo;",
1080 (void*)nativeInitialize },
1081 {"nativeSendMessage",
1083 (void*)nativeSendMessage }
1086 }//namespace android
1088 using namespace android;
1090 int register_android_hardware_location_ContextHubService(JNIEnv *env)
1092 RegisterMethodsOrDie(env, "android/hardware/location/ContextHubService",
1093 gContextHubServiceMethods, NELEM(gContextHubServiceMethods));