OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / core / jni / android_hardware_location_ContextHubService.cpp
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 #include <unordered_map>
30 #include <queue>
31
32 #include <cutils/log.h>
33
34 #include "JNIHelp.h"
35 #include "core_jni_helpers.h"
36
37 static constexpr int OS_APP_ID = -1;
38 static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
39
40 static constexpr int MIN_APP_ID = 1;
41 static constexpr int MAX_APP_ID = 128;
42
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;
48
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;
52
53 namespace android {
54
55 namespace {
56
57 /*
58  * Finds the length of a statically-sized array using template trickery that
59  * also prevents it from being applied to the wrong type.
60  */
61 template <typename T, size_t N>
62 constexpr size_t array_length(T (&)[N]) { return N; }
63
64 struct jniInfo_s {
65     JavaVM *vm;
66     jclass contextHubInfoClass;
67     jclass contextHubServiceClass;
68     jclass memoryRegionsClass;
69
70     jobject jContextHubService;
71
72     jmethodID msgReceiptCallBack;
73
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;
89
90     jmethodID contextHubServiceMsgReceiptCallback;
91     jmethodID contextHubServiceAddAppInstance;
92     jmethodID contextHubServiceDeleteAppInstance;
93 };
94
95 struct context_hub_info_s {
96     uint32_t *cookies;
97     int numHubs;
98     const struct context_hub_t *hubs;
99     struct context_hub_module_t *contextHubModule;
100 };
101
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
107 };
108
109 /*
110  * TODO(ashutoshj): From original code review:
111  *
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:
114  * class TxnManager {
115  *  public:
116  *   TxnManager();
117  *   ~TxnManager();
118  *   int add(hub_message_e identifier, void *data);
119  *   int close();
120  *   bool isPending() const;
121  *   int fetchData(hub_message_e *identifier, void **data) const;
122  *
123  *  private:
124  *   bool mPending;
125  *   mutable std::mutex mLock;
126  *   hub_message_e mIdentifier;
127  *   void *mData;
128  * };
129  *
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);
134  *    mPending = true;
135  *    mData = txnData;
136  *    mIdentifier = txnIdentifier;
137  *    return 0;
138  *  }
139  * And then calling code would look like:
140  *    if (!db.txnManager.add(CONTEXT_HUB_LOAD_APP, txnInfo)) {
141  *
142  * This would make it clearer the nothing is manipulating any state within TxnManager
143  * unsafely and outside of these couple of calls.
144  */
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
150 };
151
152 struct contextHubServiceDb_s {
153     int initialized;
154     context_hub_info_s hubInfo;
155     jniInfo_s jniInfo;
156     std::queue<int> freeIds;
157     std::unordered_map<int, app_instance_info_s> appInstances;
158     txnManager_s txnManager;
159 };
160
161 }  // unnamed namespace
162
163 static contextHubServiceDb_s db;
164
165 static bool initTxnManager() {
166     txnManager_s *mgr = &db.txnManager;
167
168     mgr->txnData = nullptr;
169     mgr->txnPending = false;
170     return true;
171 }
172
173 static int addTxn(hub_messages_e txnIdentifier, void *txnData) {
174     txnManager_s *mgr = &db.txnManager;
175
176     std::lock_guard<std::mutex>lock(mgr->m);
177
178     mgr->txnPending = true;
179     mgr->txnData = txnData;
180     mgr->txnIdentifier = txnIdentifier;
181
182     return 0;
183 }
184
185 static int closeTxn() {
186     txnManager_s *mgr = &db.txnManager;
187     std::lock_guard<std::mutex>lock(mgr->m);
188     mgr->txnPending = false;
189     free(mgr->txnData);
190     mgr->txnData = nullptr;
191
192     return 0;
193 }
194
195 static bool isTxnPending() {
196     txnManager_s *mgr = &db.txnManager;
197     std::lock_guard<std::mutex>lock(mgr->m);
198     return mgr->txnPending;
199 }
200
201 static int fetchTxnData(hub_messages_e *id, void **data) {
202     txnManager_s *mgr = &db.txnManager;
203
204     if (!id || !data) {
205         ALOGW("Null params id %p, data %p", id, data);
206         return -1;
207     }
208
209     std::lock_guard<std::mutex>lock(mgr->m);
210     if (!mgr->txnPending) {
211         ALOGW("No Transactions pending");
212         return -1;
213     }
214
215     // else
216     *id = mgr->txnIdentifier;
217     *data = mgr->txnData;
218     return 0;
219 }
220
221 int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
222                          void *cookie);
223
224 const context_hub_t *get_hub_info(int hubHandle) {
225     if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
226         return &db.hubInfo.hubs[hubHandle];
227     }
228     return nullptr;
229 }
230
231 static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
232     const context_hub_t *info = get_hub_info(hubHandle);
233
234     if (info) {
235         return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
236     } else {
237         ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
238         return -1;
239     }
240 }
241
242 static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
243     const context_hub_t *info = get_hub_info(hubHandle);
244
245     if (info) {
246         msg->app_name = info->os_app_name;
247         return 0;
248     } else {
249         ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
250         return -1;
251     }
252 }
253
254 static int get_hub_id_for_hub_handle(int hubHandle) {
255     if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
256       return -1;
257     } else {
258       return db.hubInfo.hubs[hubHandle].hub_id;
259     }
260 }
261
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);
265         return -1;
266     }
267
268     return db.appInstances[id].hubHandle;
269 }
270
271 static int get_hub_id_for_app_instance(int id) {
272     int hubHandle = get_hub_handle_for_app_instance(id);
273
274     if (hubHandle < 0) {
275         return -1;
276     }
277
278     return db.hubInfo.hubs[hubHandle].hub_id;
279 }
280
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;
286         }
287     }
288     ALOGD("Cannot find app for app instance %" PRIu64 ".", app_id);
289     return -1;
290 }
291
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);
295         return -1;
296     }
297
298     msg->app_name = db.appInstances[id].appInfo.app_name;
299     return 0;
300 }
301
302 static void query_hub_for_apps(uint64_t appId, uint32_t hubHandle) {
303     hub_message_t msg;
304     query_apps_request_t queryMsg;
305
306     queryMsg.app_name.id = NANOAPP_VENDOR_ALL_APPS;
307
308     msg.message_type = CONTEXT_HUB_QUERY_APPS;
309     msg.message_len  = sizeof(queryMsg);
310     msg.message = &queryMsg;
311
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);
316     }
317 }
318
319 static void sendQueryForApps(uint64_t appId) {
320     for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
321         query_hub_for_apps(appId, i);
322     }
323 }
324
325 static int return_id(int id) {
326     // Note : This method is not thread safe.
327     // id returned is guaranteed to be in use
328     if (id >= 0) {
329         db.freeIds.push(id);
330         return 0;
331     }
332
333     return -1;
334 }
335
336 static int generate_id() {
337     // Note : This method is not thread safe.
338     int retVal = -1;
339
340     if (!db.freeIds.empty()) {
341         retVal = db.freeIds.front();
342         db.freeIds.pop();
343     }
344
345     return retVal;
346 }
347
348
349 static int add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
350         int appInstanceHandle, JNIEnv *env) {
351
352     ALOGI("Loading App");
353
354     // Not checking if the apps are indeed distinct
355     app_instance_info_s entry;
356     assert(appInfo);
357
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",
362                   appInstanceHandle);
363             return -1;
364         }
365     }
366
367     entry.appInfo = *appInfo;
368
369     entry.instanceId = appInstanceHandle;
370     entry.truncName = appInfo->app_name.id;
371     entry.hubHandle = hubHandle;
372
373     db.appInstances[appInstanceHandle] = entry;
374
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);
380
381     ALOGW("Added App 0x%" PRIx64 " on hub Handle %" PRId32
382           " as appInstance %d", entry.truncName,
383           entry.hubHandle, appInstanceHandle);
384
385     return appInstanceHandle;
386 }
387
388 int delete_app_instance(int id, JNIEnv *env) {
389     if (!db.appInstances.count(id)) {
390         ALOGW("Cannot find App id : %d", id);
391         return -1;
392     }
393
394     return_id(id);
395     db.appInstances.erase(id);
396     if (env->CallIntMethod(db.jniInfo.jContextHubService,
397                        db.jniInfo.contextHubServiceDeleteAppInstance,
398                        id) != 0) {
399         ALOGW("Could not delete App id : %d", id);
400         return -1;
401     }
402
403     ALOGI("Deleted App id : %d", id);
404
405     return 0;
406 }
407
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();
411
412     if (!txnInfo || instanceId < 0) {
413         return_id(instanceId);
414         free(txnInfo);
415         return -1;
416     }
417
418     txnInfo->truncName = appId;
419     txnInfo->hubHandle = hubHandle;
420     txnInfo->instanceId = instanceId;
421
422     txnInfo->appInfo.app_name.id = appId;
423     txnInfo->appInfo.num_mem_ranges = 0;
424     txnInfo->appInfo.version = -1; // Awaited
425
426     if (addTxn(CONTEXT_HUB_LOAD_APP, txnInfo) != 0) {
427         return_id(instanceId);
428         free(txnInfo);
429         return -1;
430     }
431
432     return 0;
433 }
434
435 static int startUnloadAppTxn(uint32_t appInstanceHandle) {
436     uint32_t *txnData = (uint32_t *) malloc(sizeof(uint32_t));
437     if (!txnData) {
438         ALOGW("Cannot allocate memory to start unload transaction");
439         return -1;
440     }
441
442     *txnData = appInstanceHandle;
443
444     if (addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) {
445         free(txnData);
446         ALOGW("Cannot start transaction to unload app");
447         return -1;
448     }
449
450     return 0;
451 }
452
453 static void initContextHubService() {
454     int err = 0;
455     db.hubInfo.hubs = nullptr;
456     db.hubInfo.numHubs = 0;
457     int i;
458
459     err = hw_get_module(CONTEXT_HUB_MODULE_ID,
460                         (hw_module_t const**)(&db.hubInfo.contextHubModule));
461
462     if (err) {
463       ALOGE("** Could not load %s module : err %s", CONTEXT_HUB_MODULE_ID,
464             strerror(-err));
465     }
466
467     // Prep for storing app info
468     for(i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
469         db.freeIds.push(i);
470     }
471
472     initTxnManager();
473     if (db.hubInfo.contextHubModule) {
474         int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
475                                                                  &db.hubInfo.hubs);
476         ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
477         db.hubInfo.numHubs = retNumHubs;
478
479         if (db.hubInfo.numHubs > 0) {
480             db.hubInfo.numHubs = retNumHubs;
481             db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
482
483             if (!db.hubInfo.cookies) {
484                 ALOGW("Ran out of memory allocating cookies, bailing");
485                 return;
486             }
487
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) {
494                 }
495             }
496         }
497
498         sendQueryForApps(ALL_APPS);
499     } else {
500         ALOGW("No Context Hub Module present");
501     }
502 }
503
504 static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_t msgLen) {
505     JNIEnv *env;
506
507     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
508       return -1;
509     }
510
511     jbyteArray jmsg = env->NewByteArray(msgLen);
512     if (jmsg == nullptr) {
513         ALOGW("Can't allocate %zu byte array", msgLen);
514         return -1;
515     }
516     jintArray jheader = env->NewIntArray(headerLen);
517     if (jheader == nullptr) {
518         env->DeleteLocalRef(jmsg);
519         ALOGW("Can't allocate %zu int array", headerLen);
520         return -1;
521     }
522
523     env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
524     env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
525
526     int ret = (env->CallIntMethod(db.jniInfo.jContextHubService,
527                           db.jniInfo.contextHubServiceMsgReceiptCallback,
528                           jheader, jmsg) != 0);
529     env->DeleteLocalRef(jmsg);
530     env->DeleteLocalRef(jheader);
531
532     return ret;
533 }
534
535 int handle_query_apps_response(const uint8_t *msg, int msgLen,
536                                uint32_t hubHandle) {
537     JNIEnv *env;
538     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
539             return -1;
540     }
541
542     int numApps = msgLen/sizeof(hub_app_info);
543     hub_app_info info;
544     const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
545
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);
552     }
553
554     return 0;
555 }
556
557 static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
558                              status_response_t *rsp, int8_t *additionalData,
559                              size_t additionalDataLen) {
560     JNIEnv *env;
561
562     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
563         ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32, msgType);
564         return;
565     }
566
567     uint32_t header[MSG_HEADER_SIZE];
568     memset(header, 0, sizeof(header));
569
570     if (!additionalData) {
571         additionalDataLen = 0; // clamp
572     }
573     int msgLen = 1 + additionalDataLen;
574
575     int8_t *msg = new int8_t[msgLen];
576
577     if (!msg) {
578         ALOGW("Unexpected : Ran out of memory, cannot send response");
579         return;
580     }
581
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;
586
587     msg[0] = rsp->result;
588
589     if (additionalData) {
590         memcpy(&msg[1], additionalData, additionalDataLen);
591     }
592
593     jbyteArray jmsg = env->NewByteArray(msgLen);
594     jintArray jheader = env->NewIntArray(sizeof(header));
595
596     env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
597     env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
598
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]);
602
603     env->CallIntMethod(db.jniInfo.jContextHubService,
604                        db.jniInfo.contextHubServiceMsgReceiptCallback,
605                        jheader, jmsg);
606
607     delete[] msg;
608 }
609
610 void closeUnloadTxn(bool success) {
611     void *txnData = nullptr;
612     hub_messages_e txnId;
613
614     if (success && fetchTxnData(&txnId, &txnData) == 0 &&
615         txnId == CONTEXT_HUB_UNLOAD_APP) {
616         db.appInstances.erase(*(uint32_t *)txnData);
617     } else {
618         ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
619     }
620
621     closeTxn();
622 }
623
624 void closeLoadTxn(bool success, int *appInstanceHandle) {
625     void *txnData;
626     hub_messages_e txnId;
627
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;
632
633         JNIEnv *env;
634         if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) {
635             add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
636         } else {
637             ALOGW("Could not attach to JVM !");
638         }
639         sendQueryForApps(info->appInfo.app_name.id);
640     } else {
641         ALOGW("Could not load the app successfully ! Unexpected failure");
642     }
643
644     closeTxn();
645 }
646
647 static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
648                             status_response_t *rsp) {
649     // Workaround a bug in some HALs
650     if (msgLen == 1) {
651         rsp->result = msg[0];
652         return true;
653     }
654
655     if (!msg || msgLen != sizeof(*rsp)) {
656         ALOGW("Received invalid response %p of size %zu", msg, msgLen);
657         return false;
658     }
659
660     memcpy(rsp, msg, sizeof(*rsp));
661
662     // No sanity checks on return values
663     return true;
664 }
665
666 static void invalidateNanoApps(uint32_t hubHandle) {
667     JNIEnv *env;
668
669     if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
670         ALOGW("Could not attach to JVM !");
671     }
672
673     auto end = db.appInstances.end();
674     for (auto current = db.appInstances.begin(); current != end; ) {
675         app_instance_info_s info = current->second;
676         current++;
677         if (info.hubHandle == hubHandle) {
678              delete_app_instance(info.instanceId, env);
679         }
680     }
681 }
682
683 static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
684                              const uint8_t *msg, int msgLen) {
685     int retVal = -1;
686
687     ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d",
688           hubHandle, msgType, msgLen);
689
690     struct status_response_t rsp;
691
692     switch(msgType) {
693
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);
707               } else {
708                   passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
709               }
710               retVal = 0;
711           }
712           break;
713
714       case CONTEXT_HUB_QUERY_APPS:
715           rsp.result = 0;
716           retVal = handle_query_apps_response(msg, msgLen, hubHandle);
717           passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
718           break;
719
720       case CONTEXT_HUB_QUERY_MEMORY:
721           // Deferring this use
722           retVal = 0;
723           break;
724
725       case CONTEXT_HUB_OS_REBOOT:
726           if (isValidOsStatus(msg, msgLen, &rsp)) {
727               rsp.result = 0;
728               ALOGW("Context Hub handle %d restarted", hubHandle);
729               closeTxn();
730               passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
731               invalidateNanoApps(hubHandle);
732               query_hub_for_apps(ALL_APPS, hubHandle);
733               retVal = 0;
734           }
735           break;
736
737       default:
738           retVal = -1;
739           break;
740     }
741
742     return retVal;
743 }
744
745 static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
746     int *ptr = (int *)cookie;
747
748     if (!ptr || *ptr >= db.hubInfo.numHubs) {
749         return false;
750     }
751
752     if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
753         return false;
754     } else {
755         return true;
756     }
757 }
758
759
760 int context_hub_callback(uint32_t hubId,
761                          const struct hub_message_t *msg,
762                          void *cookie) {
763     if (!msg) {
764         ALOGW("NULL message");
765         return -1;
766     }
767     if (!sanity_check_cookie(cookie, hubId)) {
768         ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
769               hubId, cookie);
770
771         return -1;
772     }
773
774
775     uint32_t messageType = msg->message_type;
776     uint32_t hubHandle = *(uint32_t*) cookie;
777
778     if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
779         handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
780     } else {
781         int appHandle = get_app_instance_for_app_id(msg->app_name.id);
782         if (appHandle < 0) {
783             ALOGE("Filtering out message due to invalid App Instance.");
784         } else {
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);
790         }
791     }
792
793     return 0;
794 }
795
796 static int init_jni(JNIEnv *env, jobject instance) {
797
798     if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
799         return -1;
800     }
801
802     db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
803
804     db.jniInfo.contextHubInfoClass =
805             env->FindClass("android/hardware/location/ContextHubInfo");
806
807     db.jniInfo.contextHubServiceClass =
808             env->FindClass("android/hardware/location/ContextHubService");
809
810     db.jniInfo.memoryRegionsClass =
811             env->FindClass("android/hardware/location/MemoryRegion");
812
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");
820
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");
857
858
859     db.jniInfo.contextHubServiceMsgReceiptCallback =
860             env->GetMethodID(db.jniInfo.contextHubServiceClass, "onMessageReceipt",
861                                "([I[B)I");
862     db.jniInfo.contextHubInfoSetName =
863             env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
864             "(Ljava/lang/String;)V");
865
866     db.jniInfo.contextHubServiceAddAppInstance =
867                  env->GetMethodID(db.jniInfo.contextHubServiceClass,
868                                     "addAppInstance", "(IIJI)I");
869
870     db.jniInfo.contextHubServiceDeleteAppInstance =
871                  env->GetMethodID(db.jniInfo.contextHubServiceClass,
872                                     "deleteAppInstance", "(I)I");
873
874     return 0;
875 }
876
877 static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t *hub) {
878     jstring jstrBuf;
879     jintArray jintBuf;
880     jobjectArray jmemBuf;
881
882     jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
883                                   db.jniInfo.contextHubInfoCtor);
884     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
885
886     jstrBuf = env->NewStringUTF(hub->name);
887     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
888     env->DeleteLocalRef(jstrBuf);
889
890     jstrBuf = env->NewStringUTF(hub->vendor);
891     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
892     env->DeleteLocalRef(jstrBuf);
893
894     jstrBuf = env->NewStringUTF(hub->toolchain);
895     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
896     env->DeleteLocalRef(jstrBuf);
897
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);
909
910
911     jintBuf = env->NewIntArray(hub->num_connected_sensors);
912     int *connectedSensors = new int[hub->num_connected_sensors];
913
914     if (!connectedSensors) {
915       ALOGW("Cannot allocate memory! Unexpected");
916       assert(false);
917     } else {
918       for (unsigned int i = 0; i < hub->num_connected_sensors; i++) {
919         connectedSensors[i] = hub->connected_sensors[i].sensor_id;
920       }
921     }
922
923     env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
924                            connectedSensors);
925
926     env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
927     env->DeleteLocalRef(jintBuf);
928
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);
934
935
936     delete[] connectedSensors;
937     return jHub;
938 }
939
940 static jobjectArray nativeInitialize(JNIEnv *env, jobject instance)
941 {
942     jobject hub;
943     jobjectArray retArray;
944
945     if (init_jni(env, instance) < 0) {
946         return nullptr;
947     }
948
949     initContextHubService();
950
951     if (db.hubInfo.numHubs > 1) {
952       ALOGW("Clamping the number of hubs to 1");
953       db.hubInfo.numHubs = 1;
954     }
955
956     retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
957
958     for(int i = 0; i < db.hubInfo.numHubs; i++) {
959         hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
960         env->SetObjectArrayElement(retArray, i, hub);
961     }
962
963     return retArray;
964 }
965
966 static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
967                               jbyteArray data_) {
968     jint retVal = -1; // Default to failure
969
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_);
974
975     if (numHeaderElements < MSG_HEADER_SIZE) {
976         ALOGW("Malformed header len");
977         return -1;
978     }
979
980     uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
981     uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
982     int hubHandle = -1;
983     int hubId;
984     uint64_t appId;
985
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) {
990             return -1;
991         }
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;
995
996         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
997     } else {
998         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
999     }
1000
1001     if (hubHandle < 0) {
1002         ALOGD("Invalid hub Handle %d", hubHandle);
1003         return -1;
1004     }
1005
1006     if (msgType == CONTEXT_HUB_LOAD_APP ||
1007         msgType == CONTEXT_HUB_UNLOAD_APP) {
1008
1009         if (isTxnPending()) {
1010             ALOGW("Cannot load or unload app while a transaction is pending !");
1011             return -1;
1012         }
1013
1014         if (msgType == CONTEXT_HUB_LOAD_APP) {
1015             if (startLoadAppTxn(appId, hubHandle) != 0) {
1016                 ALOGW("Cannot Start Load Transaction");
1017                 return -1;
1018             }
1019         } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1020             if (startUnloadAppTxn(appInstanceHandle) != 0) {
1021                 ALOGW("Cannot Start UnLoad Transaction");
1022                 return -1;
1023             }
1024         }
1025     }
1026
1027     bool setAddressSuccess = false;
1028     hub_message_t msg;
1029
1030     msg.message_type = msgType;
1031
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);
1037     } else {
1038         msg.message_len = dataBufferLength;
1039         msg.message = data;
1040
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);
1044         } else {
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]);
1047         }
1048     }
1049
1050     if (setAddressSuccess && hubId >= 0) {
1051         ALOGD("Asking HAL to remove app");
1052         retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
1053     } else {
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);
1058     }
1059
1060     if (retVal != 0) {
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);
1066         }
1067     }
1068
1069     env->ReleaseIntArrayElements(header_, header, 0);
1070     env->ReleaseByteArrayElements(data_, data, 0);
1071
1072     return retVal;
1073 }
1074
1075 //--------------------------------------------------------------------------------------------------
1076 //
1077 static const JNINativeMethod gContextHubServiceMethods[] = {
1078     {"nativeInitialize",
1079              "()[Landroid/hardware/location/ContextHubInfo;",
1080              (void*)nativeInitialize },
1081     {"nativeSendMessage",
1082             "([I[B)I",
1083             (void*)nativeSendMessage }
1084 };
1085
1086 }//namespace android
1087
1088 using namespace android;
1089
1090 int register_android_hardware_location_ContextHubService(JNIEnv *env)
1091 {
1092     RegisterMethodsOrDie(env, "android/hardware/location/ContextHubService",
1093             gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
1094
1095     return 0;
1096 }