blob: 8eb39e1aac580e7651a6ccc87424ce868b900243 [file] [log] [blame]
Peng Xu9ff7d222016-02-11 13:02:05 -08001/*
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
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070019#define LOG_NDEBUG 0
20#define LOG_TAG "ContextHubService"
21
22#include <inttypes.h>
23#include <jni.h>
Ashutosh Joshi54787a52016-04-27 11:19:16 -070024#include <mutex>
Peng Xu9ff7d222016-02-11 13:02:05 -080025#include <string.h>
26#include <stdint.h>
27#include <stdio.h>
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070028#include <stdlib.h>
Greg Kaiser29e86802016-08-25 23:04:08 -070029
30// TOOD: On master, alphabetize these and move <mutex> into this
31// grouping.
32#include <chrono>
Ashutosh Joshi54787a52016-04-27 11:19:16 -070033#include <unordered_map>
34#include <queue>
Peng Xu9ff7d222016-02-11 13:02:05 -080035
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070036#include <cutils/log.h>
37
Peng Xu9ff7d222016-02-11 13:02:05 -080038#include "JNIHelp.h"
39#include "core_jni_helpers.h"
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070040
Greg Kaiserf8210792016-08-18 16:59:12 -070041static constexpr jint OS_APP_ID = -1;
Greg Kaiser9d4d8812016-08-17 16:27:26 -070042static constexpr jint INVALID_APP_ID = -2;
Ashutosh Joshi54787a52016-04-27 11:19:16 -070043static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070044
Greg Kaiserf8210792016-08-18 16:59:12 -070045static constexpr jint MIN_APP_ID = 1;
46static constexpr jint MAX_APP_ID = 128;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070047
Ashutosh Joshi54787a52016-04-27 11:19:16 -070048static constexpr size_t MSG_HEADER_SIZE = 4;
49static constexpr size_t HEADER_FIELD_MSG_TYPE = 0;
50static constexpr size_t HEADER_FIELD_MSG_VERSION = 1;
51static constexpr size_t HEADER_FIELD_HUB_HANDLE = 2;
52static constexpr size_t HEADER_FIELD_APP_INSTANCE = 3;
53
54static constexpr size_t HEADER_FIELD_LOAD_APP_ID_LO = MSG_HEADER_SIZE;
55static constexpr size_t HEADER_FIELD_LOAD_APP_ID_HI = MSG_HEADER_SIZE + 1;
56static constexpr size_t MSG_HEADER_SIZE_LOAD_APP = MSG_HEADER_SIZE + 2;
Peng Xu9ff7d222016-02-11 13:02:05 -080057
Greg Kaiser29e86802016-08-25 23:04:08 -070058// Monotonically increasing clock we use to determine if we can cancel
59// a transaction.
60using std::chrono::steady_clock;
61
Peng Xu9ff7d222016-02-11 13:02:05 -080062namespace android {
63
64namespace {
65
Peng Xu9ff7d222016-02-11 13:02:05 -080066/*
67 * Finds the length of a statically-sized array using template trickery that
68 * also prevents it from being applied to the wrong type.
69 */
70template <typename T, size_t N>
71constexpr size_t array_length(T (&)[N]) { return N; }
72
73struct jniInfo_s {
74 JavaVM *vm;
75 jclass contextHubInfoClass;
76 jclass contextHubServiceClass;
77 jclass memoryRegionsClass;
78
79 jobject jContextHubService;
80
81 jmethodID msgReceiptCallBack;
82
83 jmethodID contextHubInfoCtor;
84 jmethodID contextHubInfoSetId;
85 jmethodID contextHubInfoSetName;
86 jmethodID contextHubInfoSetVendor;
87 jmethodID contextHubInfoSetToolchain;
88 jmethodID contextHubInfoSetPlatformVersion;
89 jmethodID contextHubInfoSetStaticSwVersion;
90 jmethodID contextHubInfoSetToolchainVersion;
91 jmethodID contextHubInfoSetPeakMips;
92 jmethodID contextHubInfoSetStoppedPowerDrawMw;
93 jmethodID contextHubInfoSetSleepPowerDrawMw;
94 jmethodID contextHubInfoSetPeakPowerDrawMw;
95 jmethodID contextHubInfoSetSupportedSensors;
96 jmethodID contextHubInfoSetMemoryRegions;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070097 jmethodID contextHubInfoSetMaxPacketLenBytes;
Peng Xu9ff7d222016-02-11 13:02:05 -080098
99 jmethodID contextHubServiceMsgReceiptCallback;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700100 jmethodID contextHubServiceAddAppInstance;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700101 jmethodID contextHubServiceDeleteAppInstance;
Peng Xu9ff7d222016-02-11 13:02:05 -0800102};
103
104struct context_hub_info_s {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700105 uint32_t *cookies;
Peng Xu9ff7d222016-02-11 13:02:05 -0800106 int numHubs;
107 const struct context_hub_t *hubs;
108 struct context_hub_module_t *contextHubModule;
109};
110
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700111struct app_instance_info_s {
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700112 uint64_t truncName; // Possibly truncated name for logging
113 uint32_t hubHandle; // Id of the hub this app is on
Greg Kaiserf8210792016-08-18 16:59:12 -0700114 jint instanceId; // system wide unique instance id - assigned
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700115 struct hub_app_info appInfo; // returned from the HAL
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700116};
117
Greg Kaiser29e86802016-08-25 23:04:08 -0700118
119// If a transaction takes longer than this, we'll allow it to be
120// canceled by a new transaction. Note we do _not_ automatically
121// cancel a transaction after this much time. We can have a
122// legal transaction which takes longer than this amount of time,
123// as long as no other new transactions are attempted after this
124// time has expired.
125// TODO(b/31105001): Establish a clean timing approach for all
126// of our HAL interactions.
127constexpr auto kMinTransactionCancelTime = std::chrono::seconds(29);
128
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700129/*
130 * TODO(ashutoshj): From original code review:
131 *
132 * So, I feel like we could possible do a better job of organizing this code,
133 * and being more C++-y. Consider something like this:
134 * class TxnManager {
135 * public:
136 * TxnManager();
137 * ~TxnManager();
138 * int add(hub_message_e identifier, void *data);
139 * int close();
140 * bool isPending() const;
141 * int fetchData(hub_message_e *identifier, void **data) const;
142 *
143 * private:
144 * bool mPending;
145 * mutable std::mutex mLock;
146 * hub_message_e mIdentifier;
147 * void *mData;
148 * };
149 *
150 * And then, for example, we'd have things like:
151 * TxnManager::TxnManager() : mPending(false), mLock(), mIdentifier(), mData(nullptr) {}
152 * int TxnManager::add(hub_message_e identifier, void *data) {
153 * std::lock_guard<std::mutex> lock(mLock);
154 * mPending = true;
155 * mData = txnData;
156 * mIdentifier = txnIdentifier;
157 * return 0;
158 * }
159 * And then calling code would look like:
160 * if (!db.txnManager.add(CONTEXT_HUB_LOAD_APP, txnInfo)) {
161 *
162 * This would make it clearer the nothing is manipulating any state within TxnManager
163 * unsafely and outside of these couple of calls.
164 */
165struct txnManager_s {
166 bool txnPending; // Is a transaction pending
167 std::mutex m; // mutex for manager
168 hub_messages_e txnIdentifier; // What are we doing
169 void *txnData; // Details
Greg Kaiser29e86802016-08-25 23:04:08 -0700170 steady_clock::time_point firstTimeTxnCanBeCanceled;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700171};
172
Peng Xu9ff7d222016-02-11 13:02:05 -0800173struct contextHubServiceDb_s {
174 int initialized;
175 context_hub_info_s hubInfo;
176 jniInfo_s jniInfo;
Greg Kaiserf8210792016-08-18 16:59:12 -0700177 std::queue<jint> freeIds;
178 std::unordered_map<jint, app_instance_info_s> appInstances;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700179 txnManager_s txnManager;
Peng Xu9ff7d222016-02-11 13:02:05 -0800180};
181
182} // unnamed namespace
183
184static contextHubServiceDb_s db;
185
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700186static bool initTxnManager() {
187 txnManager_s *mgr = &db.txnManager;
188
189 mgr->txnData = nullptr;
190 mgr->txnPending = false;
191 return true;
192}
193
194static int addTxn(hub_messages_e txnIdentifier, void *txnData) {
195 txnManager_s *mgr = &db.txnManager;
196
197 std::lock_guard<std::mutex>lock(mgr->m);
198
199 mgr->txnPending = true;
Greg Kaiser29e86802016-08-25 23:04:08 -0700200 mgr->firstTimeTxnCanBeCanceled = steady_clock::now() +
201 kMinTransactionCancelTime;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700202 mgr->txnData = txnData;
203 mgr->txnIdentifier = txnIdentifier;
204
205 return 0;
206}
207
Greg Kaiser29e86802016-08-25 23:04:08 -0700208// Only call this if you hold the db.txnManager.m lock.
209static void closeTxnUnlocked() {
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700210 txnManager_s *mgr = &db.txnManager;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700211 mgr->txnPending = false;
212 free(mgr->txnData);
213 mgr->txnData = nullptr;
Greg Kaiser29e86802016-08-25 23:04:08 -0700214}
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700215
Greg Kaiser29e86802016-08-25 23:04:08 -0700216static int closeTxn() {
217 std::lock_guard<std::mutex>lock(db.txnManager.m);
218 closeTxnUnlocked();
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700219 return 0;
220}
221
Greg Kaiser29e86802016-08-25 23:04:08 -0700222// If a transaction has been pending for longer than
223// kMinTransactionCancelTime, this call will "cancel" that
224// transaction and return that there are none pending.
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700225static bool isTxnPending() {
226 txnManager_s *mgr = &db.txnManager;
227 std::lock_guard<std::mutex>lock(mgr->m);
Greg Kaiser29e86802016-08-25 23:04:08 -0700228 if (mgr->txnPending) {
229 if (steady_clock::now() >= mgr->firstTimeTxnCanBeCanceled) {
230 ALOGW("Transaction canceled");
231 closeTxnUnlocked();
232 }
233 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700234 return mgr->txnPending;
235}
236
237static int fetchTxnData(hub_messages_e *id, void **data) {
238 txnManager_s *mgr = &db.txnManager;
239
240 if (!id || !data) {
241 ALOGW("Null params id %p, data %p", id, data);
242 return -1;
243 }
244
245 std::lock_guard<std::mutex>lock(mgr->m);
246 if (!mgr->txnPending) {
247 ALOGW("No Transactions pending");
248 return -1;
249 }
250
251 // else
252 *id = mgr->txnIdentifier;
253 *data = mgr->txnData;
254 return 0;
255}
256
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700257int context_hub_callback(uint32_t hubId, const struct hub_message_t *msg,
Peng Xu9ff7d222016-02-11 13:02:05 -0800258 void *cookie);
259
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700260const context_hub_t *get_hub_info(int hubHandle) {
261 if (hubHandle >= 0 && hubHandle < db.hubInfo.numHubs) {
262 return &db.hubInfo.hubs[hubHandle];
263 }
264 return nullptr;
265}
266
267static int send_msg_to_hub(const hub_message_t *msg, int hubHandle) {
268 const context_hub_t *info = get_hub_info(hubHandle);
269
270 if (info) {
271 return db.hubInfo.contextHubModule->send_message(info->hub_id, msg);
272 } else {
273 ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
274 return -1;
275 }
276}
277
278static int set_os_app_as_destination(hub_message_t *msg, int hubHandle) {
279 const context_hub_t *info = get_hub_info(hubHandle);
280
281 if (info) {
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700282 msg->app_name = info->os_app_name;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700283 return 0;
284 } else {
285 ALOGD("%s: Hub information is null for hubHandle %d", __FUNCTION__, hubHandle);
286 return -1;
287 }
288}
289
Ashutosh Joshicafdee92016-04-04 16:19:29 -0700290static int get_hub_id_for_hub_handle(int hubHandle) {
291 if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
292 return -1;
293 } else {
294 return db.hubInfo.hubs[hubHandle].hub_id;
295 }
296}
297
Greg Kaiserf8210792016-08-18 16:59:12 -0700298static int get_hub_handle_for_app_instance(jint id) {
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700299 if (!db.appInstances.count(id)) {
Greg Kaiserf8210792016-08-18 16:59:12 -0700300 ALOGD("%s: Cannot find app for app instance %" PRId32,
301 __FUNCTION__, id);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700302 return -1;
303 }
304
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700305 return db.appInstances[id].hubHandle;
306}
307
Greg Kaiserf8210792016-08-18 16:59:12 -0700308static int get_hub_id_for_app_instance(jint id) {
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700309 int hubHandle = get_hub_handle_for_app_instance(id);
310
311 if (hubHandle < 0) {
312 return -1;
313 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700314
315 return db.hubInfo.hubs[hubHandle].hub_id;
316}
317
Greg Kaiserf8210792016-08-18 16:59:12 -0700318static jint get_app_instance_for_app_id(uint64_t app_id) {
destradaa6469c232016-04-27 17:53:23 -0700319 auto end = db.appInstances.end();
320 for (auto current = db.appInstances.begin(); current != end; ++current) {
321 if (current->second.appInfo.app_name.id == app_id) {
322 return current->first;
323 }
324 }
destradaa3cd73052016-04-29 13:11:33 -0700325 ALOGD("Cannot find app for app instance %" PRIu64 ".", app_id);
destradaa6469c232016-04-27 17:53:23 -0700326 return -1;
327}
328
Greg Kaiserf8210792016-08-18 16:59:12 -0700329static int set_dest_app(hub_message_t *msg, jint id) {
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700330 if (!db.appInstances.count(id)) {
Greg Kaiserf8210792016-08-18 16:59:12 -0700331 ALOGD("%s: Cannot find app for app instance %" PRId32,
332 __FUNCTION__, id);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700333 return -1;
334 }
335
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700336 msg->app_name = db.appInstances[id].appInfo.app_name;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700337 return 0;
338}
339
Greg Kaiserf16abd92016-09-08 00:12:19 -0700340static void query_hub_for_apps(uint32_t hubHandle) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700341 hub_message_t msg;
Ashutosh Joshi848c8c42016-07-06 13:54:28 -0700342 query_apps_request_t queryMsg;
343
Greg Kaiserf16abd92016-09-08 00:12:19 -0700344 // TODO(b/30835598): When we're able to tell which request our
345 // response matches, then we should allow this to be more
346 // targetted, instead of always being every app in the
347 // system.
348 queryMsg.app_name.id = ALL_APPS;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700349
350 msg.message_type = CONTEXT_HUB_QUERY_APPS;
Ashutosh Joshi848c8c42016-07-06 13:54:28 -0700351 msg.message_len = sizeof(queryMsg);
352 msg.message = &queryMsg;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700353
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700354 ALOGD("Sending query for apps to hub %" PRIu32, hubHandle);
355 set_os_app_as_destination(&msg, hubHandle);
356 if (send_msg_to_hub(&msg, hubHandle) != 0) {
357 ALOGW("Could not query hub %" PRIu32 " for apps", hubHandle);
358 }
359}
360
Greg Kaiserf16abd92016-09-08 00:12:19 -0700361static void sendQueryForApps() {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700362 for (int i = 0; i < db.hubInfo.numHubs; i++ ) {
Greg Kaiserf16abd92016-09-08 00:12:19 -0700363 query_hub_for_apps(i);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700364 }
365}
366
Greg Kaiserf8210792016-08-18 16:59:12 -0700367static int return_id(jint id) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700368 // Note : This method is not thread safe.
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700369 // id returned is guaranteed to be in use
370 if (id >= 0) {
371 db.freeIds.push(id);
372 return 0;
373 }
374
375 return -1;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700376}
377
Greg Kaiserf8210792016-08-18 16:59:12 -0700378static jint generate_id() {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700379 // Note : This method is not thread safe.
Greg Kaiserf8210792016-08-18 16:59:12 -0700380 jint retVal = -1;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700381
382 if (!db.freeIds.empty()) {
383 retVal = db.freeIds.front();
384 db.freeIds.pop();
385 }
386
387 return retVal;
388}
389
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700390
Greg Kaiserf8210792016-08-18 16:59:12 -0700391static jint add_app_instance(const hub_app_info *appInfo, uint32_t hubHandle,
392 jint appInstanceHandle, JNIEnv *env) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700393 // Not checking if the apps are indeed distinct
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700394 app_instance_info_s entry;
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700395 assert(appInfo);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700396
Greg Kaiserb0604ec2016-09-06 22:55:53 -0700397 const char *action =
398 (db.appInstances.count(appInstanceHandle) == 0) ? "Added" : "Updated";
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700399
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700400 entry.appInfo = *appInfo;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700401
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700402 entry.instanceId = appInstanceHandle;
403 entry.truncName = appInfo->app_name.id;
404 entry.hubHandle = hubHandle;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700405
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700406 db.appInstances[appInstanceHandle] = entry;
407
Greg Kaiserf16abd92016-09-08 00:12:19 -0700408 // Finally - let the service know of this app instance, to populate
409 // the Java cache.
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700410 env->CallIntMethod(db.jniInfo.jContextHubService,
411 db.jniInfo.contextHubServiceAddAppInstance,
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700412 hubHandle, entry.instanceId, entry.truncName,
413 entry.appInfo.version);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700414
Greg Kaiserf16abd92016-09-08 00:12:19 -0700415 ALOGI("%s App 0x%" PRIx64 " on hub Handle %" PRId32
Greg Kaiserfe6d4f52016-08-19 10:24:07 -0700416 " as appInstance %" PRId32, action, entry.truncName,
Alexey Polyudovab2d4452016-04-08 09:56:35 -0700417 entry.hubHandle, appInstanceHandle);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700418
419 return appInstanceHandle;
420}
421
Greg Kaiserf8210792016-08-18 16:59:12 -0700422int delete_app_instance(jint id, JNIEnv *env) {
Greg Kaiser0d052c92016-08-18 15:55:10 -0700423 bool fullyDeleted = true;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700424
Greg Kaiser0d052c92016-08-18 15:55:10 -0700425 if (db.appInstances.count(id)) {
426 db.appInstances.erase(id);
427 } else {
Greg Kaiserf8210792016-08-18 16:59:12 -0700428 ALOGW("Cannot delete App id (%" PRId32 ") from the JNI C++ cache", id);
Greg Kaiser0d052c92016-08-18 15:55:10 -0700429 fullyDeleted = false;
430 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700431 return_id(id);
Greg Kaiser0d052c92016-08-18 15:55:10 -0700432
433 if ((env == nullptr) ||
434 (env->CallIntMethod(db.jniInfo.jContextHubService,
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700435 db.jniInfo.contextHubServiceDeleteAppInstance,
Greg Kaiser0d052c92016-08-18 15:55:10 -0700436 id) != 0)) {
Greg Kaiserf8210792016-08-18 16:59:12 -0700437 ALOGW("Cannot delete App id (%" PRId32 ") from Java cache", id);
Greg Kaiser0d052c92016-08-18 15:55:10 -0700438 fullyDeleted = false;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700439 }
440
Greg Kaiser0d052c92016-08-18 15:55:10 -0700441 if (fullyDeleted) {
Greg Kaiserf8210792016-08-18 16:59:12 -0700442 ALOGI("Deleted App id : %" PRId32, id);
Greg Kaiser0d052c92016-08-18 15:55:10 -0700443 return 0;
444 }
445 return -1;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700446}
447
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700448static int startLoadAppTxn(uint64_t appId, int hubHandle) {
449 app_instance_info_s *txnInfo = (app_instance_info_s *)malloc(sizeof(app_instance_info_s));
Greg Kaiserf8210792016-08-18 16:59:12 -0700450 jint instanceId = generate_id();
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700451
452 if (!txnInfo || instanceId < 0) {
453 return_id(instanceId);
454 free(txnInfo);
455 return -1;
456 }
457
458 txnInfo->truncName = appId;
459 txnInfo->hubHandle = hubHandle;
460 txnInfo->instanceId = instanceId;
461
462 txnInfo->appInfo.app_name.id = appId;
463 txnInfo->appInfo.num_mem_ranges = 0;
464 txnInfo->appInfo.version = -1; // Awaited
465
Ashutosh Joshi11864402016-07-15 13:46:22 -0700466 if (addTxn(CONTEXT_HUB_LOAD_APP, txnInfo) != 0) {
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700467 return_id(instanceId);
468 free(txnInfo);
469 return -1;
470 }
471
472 return 0;
473}
474
Greg Kaiserf8210792016-08-18 16:59:12 -0700475static int startUnloadAppTxn(jint appInstanceHandle) {
476 jint *txnData = (jint *) malloc(sizeof(jint));
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700477 if (!txnData) {
478 ALOGW("Cannot allocate memory to start unload transaction");
479 return -1;
480 }
481
482 *txnData = appInstanceHandle;
483
484 if (addTxn(CONTEXT_HUB_UNLOAD_APP, txnData) != 0) {
485 free(txnData);
486 ALOGW("Cannot start transaction to unload app");
487 return -1;
488 }
489
490 return 0;
491}
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700492
Peng Xu9ff7d222016-02-11 13:02:05 -0800493static void initContextHubService() {
494 int err = 0;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700495 db.hubInfo.hubs = nullptr;
Peng Xu9ff7d222016-02-11 13:02:05 -0800496 db.hubInfo.numHubs = 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800497
498 err = hw_get_module(CONTEXT_HUB_MODULE_ID,
499 (hw_module_t const**)(&db.hubInfo.contextHubModule));
500
501 if (err) {
502 ALOGE("** Could not load %s module : err %s", CONTEXT_HUB_MODULE_ID,
503 strerror(-err));
504 }
505
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700506 // Prep for storing app info
Greg Kaiserf8210792016-08-18 16:59:12 -0700507 for (jint i = MIN_APP_ID; i <= MAX_APP_ID; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700508 db.freeIds.push(i);
509 }
Ashutosh Joshiadf75e32016-03-29 09:19:56 -0700510
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700511 initTxnManager();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700512 if (db.hubInfo.contextHubModule) {
513 int retNumHubs = db.hubInfo.contextHubModule->get_hubs(db.hubInfo.contextHubModule,
514 &db.hubInfo.hubs);
515 ALOGD("ContextHubModule returned %d hubs ", retNumHubs);
516 db.hubInfo.numHubs = retNumHubs;
517
518 if (db.hubInfo.numHubs > 0) {
519 db.hubInfo.numHubs = retNumHubs;
520 db.hubInfo.cookies = (uint32_t *)malloc(sizeof(uint32_t) * db.hubInfo.numHubs);
521
522 if (!db.hubInfo.cookies) {
523 ALOGW("Ran out of memory allocating cookies, bailing");
524 return;
525 }
526
Greg Kaiserf8210792016-08-18 16:59:12 -0700527 for (int i = 0; i < db.hubInfo.numHubs; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700528 db.hubInfo.cookies[i] = db.hubInfo.hubs[i].hub_id;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700529 ALOGI("Subscribing to hubHandle %d with OS App name %" PRIu64, i, db.hubInfo.hubs[i].os_app_name.id);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700530 if (db.hubInfo.contextHubModule->subscribe_messages(db.hubInfo.hubs[i].hub_id,
531 context_hub_callback,
532 &db.hubInfo.cookies[i]) == 0) {
533 }
534 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800535 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700536
Greg Kaiserf16abd92016-09-08 00:12:19 -0700537 sendQueryForApps();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700538 } else {
539 ALOGW("No Context Hub Module present");
Peng Xu9ff7d222016-02-11 13:02:05 -0800540 }
541}
542
destradaa6469c232016-04-27 17:53:23 -0700543static int onMessageReceipt(uint32_t *header, size_t headerLen, char *msg, size_t msgLen) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800544 JNIEnv *env;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700545
546 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800547 return -1;
548 }
549
550 jbyteArray jmsg = env->NewByteArray(msgLen);
Greg Kaiserbece5992016-05-09 10:23:56 -0700551 if (jmsg == nullptr) {
552 ALOGW("Can't allocate %zu byte array", msgLen);
553 return -1;
554 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800555 jintArray jheader = env->NewIntArray(headerLen);
Greg Kaiserbece5992016-05-09 10:23:56 -0700556 if (jheader == nullptr) {
557 env->DeleteLocalRef(jmsg);
558 ALOGW("Can't allocate %zu int array", headerLen);
559 return -1;
560 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800561
562 env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
563 env->SetIntArrayRegion(jheader, 0, headerLen, (jint *)header);
564
Greg Kaiserbece5992016-05-09 10:23:56 -0700565 int ret = (env->CallIntMethod(db.jniInfo.jContextHubService,
Peng Xu9ff7d222016-02-11 13:02:05 -0800566 db.jniInfo.contextHubServiceMsgReceiptCallback,
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700567 jheader, jmsg) != 0);
Greg Kaiserbece5992016-05-09 10:23:56 -0700568 env->DeleteLocalRef(jmsg);
569 env->DeleteLocalRef(jheader);
570
571 return ret;
Peng Xu9ff7d222016-02-11 13:02:05 -0800572}
573
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700574int handle_query_apps_response(const uint8_t *msg, int msgLen,
575 uint32_t hubHandle) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700576 JNIEnv *env;
577 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
578 return -1;
579 }
580
Greg Kaiserf16abd92016-09-08 00:12:19 -0700581 int numApps = msgLen / sizeof(hub_app_info);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700582 const hub_app_info *unalignedInfoAddr = (const hub_app_info*)msg;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700583
Greg Kaiserf16abd92016-09-08 00:12:19 -0700584 // We use this information to sync our JNI and Java caches of nanoapp info.
585 // We want to accomplish two things here:
586 // 1) Remove entries from our caches which are stale, and pertained to
587 // apps no longer running on Context Hub.
588 // 2) Populate our caches with the latest information of all these apps.
589
590 // We make a couple of assumptions here:
591 // A) The JNI and Java caches are in sync with each other (this isn't
592 // necessarily true; any failure of a single call into Java land to
593 // update its cache will leave that cache in a bad state. For NYC,
594 // we're willing to tolerate this for now).
595 // B) The total number of apps is relatively small, so horribly inefficent
596 // algorithms aren't too painful.
597 // C) We're going to call this relatively infrequently, so its inefficency
598 // isn't a big impact.
599
600
601 // (1). Looking for stale cache entries. Yes, this is O(N^2). See
602 // assumption (B). Per assumption (A), it is sufficient to iterate
603 // over just the JNI cache.
604 auto end = db.appInstances.end();
605 for (auto current = db.appInstances.begin(); current != end; ) {
606 app_instance_info_s cache_entry = current->second;
607 // We perform our iteration here because if we call
608 // delete_app_instance() below, it will erase() this entry.
609 current++;
610 bool entryIsStale = true;
611 for (int i = 0; i < numApps; i++) {
612 // We use memcmp since this could be unaligned.
613 if (memcmp(&unalignedInfoAddr[i].app_name.id,
614 &cache_entry.appInfo.app_name.id,
615 sizeof(cache_entry.appInfo.app_name.id)) == 0) {
616 // We found a match; this entry is current.
617 entryIsStale = false;
618 break;
619 }
620 }
621 if (entryIsStale) {
622 delete_app_instance(cache_entry.instanceId, env);
623 }
624 }
625
626 // (2). Update our caches with the latest.
627 for (int i = 0; i < numApps; i++) {
628 hub_app_info query_info;
629 memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700630 // We will only have one instance of the app
631 // TODO : Change this logic once we support multiple instances of the same app
Greg Kaiserf16abd92016-09-08 00:12:19 -0700632 jint appInstance = get_app_instance_for_app_id(query_info.app_name.id);
633 if (appInstance == -1) {
634 // This is a previously unknown app, let's allocate an "id" for it.
635 appInstance = generate_id();
636 }
637 add_app_instance(&query_info, hubHandle, appInstance, env);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700638 }
639
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700640 return 0;
641}
642
Greg Kaiserf8210792016-08-18 16:59:12 -0700643// TODO(b/30807327): Do not use raw bytes for additional data. Use the
644// JNI interfaces for the appropriate types.
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700645static void passOnOsResponse(uint32_t hubHandle, uint32_t msgType,
646 status_response_t *rsp, int8_t *additionalData,
647 size_t additionalDataLen) {
648 JNIEnv *env;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700649
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700650 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
651 ALOGW("Cannot latch to JNI env, dropping OS response %" PRIu32, msgType);
652 return;
653 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700654
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700655 uint32_t header[MSG_HEADER_SIZE];
656 memset(header, 0, sizeof(header));
657
658 if (!additionalData) {
659 additionalDataLen = 0; // clamp
660 }
661 int msgLen = 1 + additionalDataLen;
662
663 int8_t *msg = new int8_t[msgLen];
664
665 if (!msg) {
666 ALOGW("Unexpected : Ran out of memory, cannot send response");
667 return;
668 }
669
670 header[HEADER_FIELD_MSG_TYPE] = msgType;
671 header[HEADER_FIELD_MSG_VERSION] = 0;
672 header[HEADER_FIELD_HUB_HANDLE] = hubHandle;
673 header[HEADER_FIELD_APP_INSTANCE] = OS_APP_ID;
674
Greg Kaiser6d9e7f62016-08-17 16:44:14 -0700675 // Due to API constraints, at the moment we can't change the fact that
676 // we're changing our 4-byte response to a 1-byte value. But we can prevent
677 // the possible change in sign (and thus meaning) that would happen from
678 // a naive cast. Further, we can log when we're losing part of the value.
679 // TODO(b/30918279): Don't truncate this result.
680 int8_t truncatedResult;
681 bool neededToTruncate;
682 if (rsp->result < INT8_MIN) {
683 neededToTruncate = true;
684 truncatedResult = INT8_MIN;
685 } else if (rsp->result > INT8_MAX) {
686 neededToTruncate = true;
687 truncatedResult = INT8_MAX;
688 } else {
689 neededToTruncate = false;
690 // Since this value fits within an int8_t, this is a safe cast which
691 // won't change the value or sign.
692 truncatedResult = static_cast<int8_t>(rsp->result);
693 }
694 if (neededToTruncate) {
695 ALOGW("Response from Context Hub truncated. Value was %" PRId32
696 ", but giving Java layer %" PRId8,
697 rsp->result, (int)truncatedResult);
698 }
699
700 msg[0] = truncatedResult;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700701
702 if (additionalData) {
703 memcpy(&msg[1], additionalData, additionalDataLen);
704 }
705
706 jbyteArray jmsg = env->NewByteArray(msgLen);
707 jintArray jheader = env->NewIntArray(sizeof(header));
708
709 env->SetByteArrayRegion(jmsg, 0, msgLen, (jbyte *)msg);
710 env->SetIntArrayRegion(jheader, 0, sizeof(header), (jint *)header);
711
712 ALOGI("Passing msg type %" PRIu32 " from app %" PRIu32 " from hub %" PRIu32,
713 header[HEADER_FIELD_MSG_TYPE], header[HEADER_FIELD_APP_INSTANCE],
714 header[HEADER_FIELD_HUB_HANDLE]);
715
716 env->CallIntMethod(db.jniInfo.jContextHubService,
717 db.jniInfo.contextHubServiceMsgReceiptCallback,
718 jheader, jmsg);
Andrew Rossignolc3510452016-08-09 10:54:38 -0700719 env->DeleteLocalRef(jmsg);
720 env->DeleteLocalRef(jheader);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700721
722 delete[] msg;
723}
724
725void closeUnloadTxn(bool success) {
726 void *txnData = nullptr;
727 hub_messages_e txnId;
728
729 if (success && fetchTxnData(&txnId, &txnData) == 0 &&
730 txnId == CONTEXT_HUB_UNLOAD_APP) {
Greg Kaiser0d052c92016-08-18 15:55:10 -0700731 JNIEnv *env;
732 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) != JNI_OK) {
733 ALOGW("Could not attach to JVM !");
734 env = nullptr;
735 }
Greg Kaiserf8210792016-08-18 16:59:12 -0700736 jint handle = *reinterpret_cast<jint *>(txnData);
Greg Kaiser0d052c92016-08-18 15:55:10 -0700737 delete_app_instance(handle, env);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700738 } else {
739 ALOGW("Could not unload the app successfully ! success %d, txnData %p", success, txnData);
740 }
741
742 closeTxn();
743}
744
Greg Kaiser9d4d8812016-08-17 16:27:26 -0700745static bool closeLoadTxn(bool success, jint *appInstanceHandle) {
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700746 void *txnData;
747 hub_messages_e txnId;
748
749 if (success && fetchTxnData(&txnId, &txnData) == 0 &&
750 txnId == CONTEXT_HUB_LOAD_APP) {
751 app_instance_info_s *info = (app_instance_info_s *)txnData;
752 *appInstanceHandle = info->instanceId;
753
754 JNIEnv *env;
755 if ((db.jniInfo.vm)->AttachCurrentThread(&env, nullptr) == JNI_OK) {
756 add_app_instance(&info->appInfo, info->hubHandle, info->instanceId, env);
757 } else {
758 ALOGW("Could not attach to JVM !");
Greg Kaiser9d4d8812016-08-17 16:27:26 -0700759 success = false;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700760 }
Greg Kaiserf16abd92016-09-08 00:12:19 -0700761 // While we just called add_app_instance above, our info->appInfo was
762 // incomplete (for example, the 'version' is hardcoded to -1). So we
763 // trigger an additional query to the CHRE, so we'll be able to get
764 // all the app "info", and have our JNI and Java caches with the
765 // full information.
766 sendQueryForApps();
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700767 } else {
768 ALOGW("Could not load the app successfully ! Unexpected failure");
Greg Kaiser9d4d8812016-08-17 16:27:26 -0700769 *appInstanceHandle = INVALID_APP_ID;
770 success = false;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700771 }
772
773 closeTxn();
Greg Kaiser9d4d8812016-08-17 16:27:26 -0700774 return success;
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700775}
776
777static bool isValidOsStatus(const uint8_t *msg, size_t msgLen,
778 status_response_t *rsp) {
779 // Workaround a bug in some HALs
780 if (msgLen == 1) {
781 rsp->result = msg[0];
782 return true;
783 }
784
785 if (!msg || msgLen != sizeof(*rsp)) {
786 ALOGW("Received invalid response %p of size %zu", msg, msgLen);
787 return false;
788 }
789
790 memcpy(rsp, msg, sizeof(*rsp));
791
792 // No sanity checks on return values
793 return true;
794}
795
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700796static int handle_os_message(uint32_t msgType, uint32_t hubHandle,
797 const uint8_t *msg, int msgLen) {
798 int retVal = -1;
799
800 ALOGD("Rcd OS message from hubHandle %" PRIu32 " type %" PRIu32 " length %d",
801 hubHandle, msgType, msgLen);
802
803 struct status_response_t rsp;
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700804
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700805 switch(msgType) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700806
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700807 case CONTEXT_HUB_APPS_ENABLE:
808 case CONTEXT_HUB_APPS_DISABLE:
809 case CONTEXT_HUB_LOAD_APP:
810 case CONTEXT_HUB_UNLOAD_APP:
811 if (isValidOsStatus(msg, msgLen, &rsp)) {
812 if (msgType == CONTEXT_HUB_LOAD_APP) {
Greg Kaiser9d4d8812016-08-17 16:27:26 -0700813 jint appInstanceHandle = INVALID_APP_ID;
814 bool appRunningOnHub = (rsp.result == 0);
815 if (!(closeLoadTxn(appRunningOnHub, &appInstanceHandle))) {
816 if (appRunningOnHub) {
817 // Now we're in an odd situation. Our nanoapp
818 // is up and running on the Context Hub. However,
819 // something went wrong in our Service code so that
820 // we're not able to properly track this nanoapp
821 // in our Service code. If we tell the Java layer
822 // things are good, it's a lie because the handle
823 // we give them will fail when used with the Service.
824 // If we tell the Java layer this failed, it's kind
825 // of a lie as well, since this nanoapp is running.
826 //
827 // We leave a more robust fix for later, and for
828 // now just tell the user things have failed.
829 //
830 // TODO(b/30835981): Make this situation better.
831 rsp.result = -1;
832 }
833 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700834 passOnOsResponse(hubHandle, msgType, &rsp, (int8_t *)(&appInstanceHandle),
835 sizeof(appInstanceHandle));
836 } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
837 closeUnloadTxn(rsp.result == 0);
838 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
839 } else {
840 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
841 }
842 retVal = 0;
843 }
844 break;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700845
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700846 case CONTEXT_HUB_QUERY_APPS:
847 rsp.result = 0;
848 retVal = handle_query_apps_response(msg, msgLen, hubHandle);
849 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
850 break;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700851
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700852 case CONTEXT_HUB_QUERY_MEMORY:
853 // Deferring this use
854 retVal = 0;
855 break;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700856
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700857 case CONTEXT_HUB_OS_REBOOT:
858 if (isValidOsStatus(msg, msgLen, &rsp)) {
859 rsp.result = 0;
860 ALOGW("Context Hub handle %d restarted", hubHandle);
Ashutosh Joshi11864402016-07-15 13:46:22 -0700861 closeTxn();
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700862 passOnOsResponse(hubHandle, msgType, &rsp, nullptr, 0);
Greg Kaiserf16abd92016-09-08 00:12:19 -0700863 query_hub_for_apps(hubHandle);
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700864 retVal = 0;
865 }
866 break;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700867
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700868 default:
869 retVal = -1;
870 break;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700871 }
872
873 return retVal;
874}
875
876static bool sanity_check_cookie(void *cookie, uint32_t hub_id) {
877 int *ptr = (int *)cookie;
878
879 if (!ptr || *ptr >= db.hubInfo.numHubs) {
880 return false;
881 }
882
883 if (db.hubInfo.hubs[*ptr].hub_id != hub_id) {
884 return false;
885 } else {
886 return true;
887 }
888}
889
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700890
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700891int context_hub_callback(uint32_t hubId,
892 const struct hub_message_t *msg,
Peng Xu9ff7d222016-02-11 13:02:05 -0800893 void *cookie) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700894 if (!msg) {
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700895 ALOGW("NULL message");
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700896 return -1;
897 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700898 if (!sanity_check_cookie(cookie, hubId)) {
899 ALOGW("Incorrect cookie %" PRId32 " for cookie %p! Bailing",
900 hubId, cookie);
901
902 return -1;
903 }
904
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700905
destradaa6469c232016-04-27 17:53:23 -0700906 uint32_t messageType = msg->message_type;
907 uint32_t hubHandle = *(uint32_t*) cookie;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700908
destradaa6469c232016-04-27 17:53:23 -0700909 if (messageType < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
Ashutosh Joshi54787a52016-04-27 11:19:16 -0700910 handle_os_message(messageType, hubHandle, (uint8_t*) msg->message, msg->message_len);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700911 } else {
Greg Kaiserf8210792016-08-18 16:59:12 -0700912 jint appHandle = get_app_instance_for_app_id(msg->app_name.id);
destradaa6469c232016-04-27 17:53:23 -0700913 if (appHandle < 0) {
914 ALOGE("Filtering out message due to invalid App Instance.");
915 } else {
916 uint32_t msgHeader[MSG_HEADER_SIZE] = {};
917 msgHeader[HEADER_FIELD_MSG_TYPE] = messageType;
918 msgHeader[HEADER_FIELD_HUB_HANDLE] = hubHandle;
919 msgHeader[HEADER_FIELD_APP_INSTANCE] = appHandle;
920 onMessageReceipt(msgHeader, MSG_HEADER_SIZE, (char*) msg->message, msg->message_len);
921 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700922 }
923
924 return 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800925}
926
927static int init_jni(JNIEnv *env, jobject instance) {
928
929 if (env->GetJavaVM(&db.jniInfo.vm) != JNI_OK) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700930 return -1;
Peng Xu9ff7d222016-02-11 13:02:05 -0800931 }
932
933 db.jniInfo.jContextHubService = env->NewGlobalRef(instance);
934
935 db.jniInfo.contextHubInfoClass =
936 env->FindClass("android/hardware/location/ContextHubInfo");
937
938 db.jniInfo.contextHubServiceClass =
939 env->FindClass("android/hardware/location/ContextHubService");
940
941 db.jniInfo.memoryRegionsClass =
942 env->FindClass("android/hardware/location/MemoryRegion");
943
Peng Xu9ff7d222016-02-11 13:02:05 -0800944 db.jniInfo.contextHubInfoCtor =
945 env->GetMethodID(db.jniInfo.contextHubInfoClass, "<init>", "()V");
946 db.jniInfo.contextHubInfoSetId =
947 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setId", "(I)V");
948 db.jniInfo.contextHubInfoSetName =
949 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
950 "(Ljava/lang/String;)V");
951
952 db.jniInfo.contextHubInfoSetVendor =
953 env->GetMethodID(db.jniInfo.contextHubInfoClass,
954 "setVendor", "(Ljava/lang/String;)V");
955 db.jniInfo.contextHubInfoSetToolchain =
956 env->GetMethodID(db.jniInfo.contextHubInfoClass,
957 "setToolchain", "(Ljava/lang/String;)V");
958 db.jniInfo.contextHubInfoSetPlatformVersion =
959 env->GetMethodID(db.jniInfo.contextHubInfoClass,
960 "setPlatformVersion", "(I)V");
961 db.jniInfo.contextHubInfoSetStaticSwVersion =
962 env->GetMethodID(db.jniInfo.contextHubInfoClass,
963 "setStaticSwVersion", "(I)V");
964 db.jniInfo.contextHubInfoSetToolchainVersion =
965 env->GetMethodID(db.jniInfo.contextHubInfoClass,
966 "setToolchainVersion", "(I)V");
967 db.jniInfo.contextHubInfoSetPeakMips =
968 env->GetMethodID(db.jniInfo.contextHubInfoClass,
969 "setPeakMips", "(F)V");
970 db.jniInfo.contextHubInfoSetStoppedPowerDrawMw =
971 env->GetMethodID(db.jniInfo.contextHubInfoClass,
972 "setStoppedPowerDrawMw", "(F)V");
973 db.jniInfo.contextHubInfoSetSleepPowerDrawMw =
974 env->GetMethodID(db.jniInfo.contextHubInfoClass,
975 "setSleepPowerDrawMw", "(F)V");
976 db.jniInfo.contextHubInfoSetPeakPowerDrawMw =
977 env->GetMethodID(db.jniInfo.contextHubInfoClass,
978 "setPeakPowerDrawMw", "(F)V");
979 db.jniInfo.contextHubInfoSetSupportedSensors =
980 env->GetMethodID(db.jniInfo.contextHubInfoClass,
981 "setSupportedSensors", "([I)V");
982 db.jniInfo.contextHubInfoSetMemoryRegions =
983 env->GetMethodID(db.jniInfo.contextHubInfoClass,
984 "setMemoryRegions", "([Landroid/hardware/location/MemoryRegion;)V");
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700985 db.jniInfo.contextHubInfoSetMaxPacketLenBytes =
986 env->GetMethodID(db.jniInfo.contextHubInfoClass,
987 "setMaxPacketLenBytes", "(I)V");
Peng Xu9ff7d222016-02-11 13:02:05 -0800988
989
990 db.jniInfo.contextHubServiceMsgReceiptCallback =
991 env->GetMethodID(db.jniInfo.contextHubServiceClass, "onMessageReceipt",
992 "([I[B)I");
993 db.jniInfo.contextHubInfoSetName =
994 env->GetMethodID(db.jniInfo.contextHubInfoClass, "setName",
995 "(Ljava/lang/String;)V");
996
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700997 db.jniInfo.contextHubServiceAddAppInstance =
998 env->GetMethodID(db.jniInfo.contextHubServiceClass,
999 "addAppInstance", "(IIJI)I");
1000
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001001 db.jniInfo.contextHubServiceDeleteAppInstance =
1002 env->GetMethodID(db.jniInfo.contextHubServiceClass,
1003 "deleteAppInstance", "(I)I");
Peng Xu9ff7d222016-02-11 13:02:05 -08001004
1005 return 0;
1006}
1007
1008static jobject constructJContextHubInfo(JNIEnv *env, const struct context_hub_t *hub) {
1009 jstring jstrBuf;
1010 jintArray jintBuf;
1011 jobjectArray jmemBuf;
1012
Peng Xu9ff7d222016-02-11 13:02:05 -08001013 jobject jHub = env->NewObject(db.jniInfo.contextHubInfoClass,
1014 db.jniInfo.contextHubInfoCtor);
1015 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetId, hub->hub_id);
1016
1017 jstrBuf = env->NewStringUTF(hub->name);
1018 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetName, jstrBuf);
Greg Kaiserbece5992016-05-09 10:23:56 -07001019 env->DeleteLocalRef(jstrBuf);
Peng Xu9ff7d222016-02-11 13:02:05 -08001020
1021 jstrBuf = env->NewStringUTF(hub->vendor);
1022 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetVendor, jstrBuf);
Greg Kaiserbece5992016-05-09 10:23:56 -07001023 env->DeleteLocalRef(jstrBuf);
Peng Xu9ff7d222016-02-11 13:02:05 -08001024
1025 jstrBuf = env->NewStringUTF(hub->toolchain);
1026 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchain, jstrBuf);
Greg Kaiserbece5992016-05-09 10:23:56 -07001027 env->DeleteLocalRef(jstrBuf);
Peng Xu9ff7d222016-02-11 13:02:05 -08001028
1029 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPlatformVersion, hub->platform_version);
1030 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetToolchainVersion, hub->toolchain_version);
1031 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakMips, hub->peak_mips);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001032 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetStoppedPowerDrawMw,
1033 hub->stopped_power_draw_mw);
1034 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSleepPowerDrawMw,
1035 hub->sleep_power_draw_mw);
1036 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetPeakPowerDrawMw,
1037 hub->peak_power_draw_mw);
1038 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMaxPacketLenBytes,
1039 hub->max_supported_msg_len);
1040
Peng Xu9ff7d222016-02-11 13:02:05 -08001041
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001042 jintBuf = env->NewIntArray(hub->num_connected_sensors);
1043 int *connectedSensors = new int[hub->num_connected_sensors];
1044
1045 if (!connectedSensors) {
1046 ALOGW("Cannot allocate memory! Unexpected");
1047 assert(false);
1048 } else {
1049 for (unsigned int i = 0; i < hub->num_connected_sensors; i++) {
1050 connectedSensors[i] = hub->connected_sensors[i].sensor_id;
1051 }
1052 }
1053
1054 env->SetIntArrayRegion(jintBuf, 0, hub->num_connected_sensors,
1055 connectedSensors);
1056
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001057 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetSupportedSensors, jintBuf);
Greg Kaiserbece5992016-05-09 10:23:56 -07001058 env->DeleteLocalRef(jintBuf);
Peng Xu9ff7d222016-02-11 13:02:05 -08001059
1060 // We are not getting the memory regions from the CH Hal - change this when it is available
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001061 jmemBuf = env->NewObjectArray(0, db.jniInfo.memoryRegionsClass, nullptr);
Peng Xu9ff7d222016-02-11 13:02:05 -08001062 // Note the zero size above. We do not need to set any elements
1063 env->CallVoidMethod(jHub, db.jniInfo.contextHubInfoSetMemoryRegions, jmemBuf);
Greg Kaiserbece5992016-05-09 10:23:56 -07001064 env->DeleteLocalRef(jmemBuf);
Peng Xu9ff7d222016-02-11 13:02:05 -08001065
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001066
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001067 delete[] connectedSensors;
Peng Xu9ff7d222016-02-11 13:02:05 -08001068 return jHub;
1069}
1070
1071static jobjectArray nativeInitialize(JNIEnv *env, jobject instance)
1072{
1073 jobject hub;
1074 jobjectArray retArray;
1075
Peng Xu9ff7d222016-02-11 13:02:05 -08001076 if (init_jni(env, instance) < 0) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001077 return nullptr;
Peng Xu9ff7d222016-02-11 13:02:05 -08001078 }
1079
Peng Xu9ff7d222016-02-11 13:02:05 -08001080 initContextHubService();
1081
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001082 if (db.hubInfo.numHubs > 1) {
1083 ALOGW("Clamping the number of hubs to 1");
1084 db.hubInfo.numHubs = 1;
1085 }
1086
1087 retArray = env->NewObjectArray(db.hubInfo.numHubs, db.jniInfo.contextHubInfoClass, nullptr);
Peng Xu9ff7d222016-02-11 13:02:05 -08001088
1089 for(int i = 0; i < db.hubInfo.numHubs; i++) {
1090 hub = constructJContextHubInfo(env, &db.hubInfo.hubs[i]);
1091 env->SetObjectArrayElement(retArray, i, hub);
1092 }
1093
1094 return retArray;
1095}
1096
1097static jint nativeSendMessage(JNIEnv *env, jobject instance, jintArray header_,
1098 jbyteArray data_) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001099 jint retVal = -1; // Default to failure
Peng Xu9ff7d222016-02-11 13:02:05 -08001100
1101 jint *header = env->GetIntArrayElements(header_, 0);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001102 unsigned int numHeaderElements = env->GetArrayLength(header_);
Peng Xu9ff7d222016-02-11 13:02:05 -08001103 jbyte *data = env->GetByteArrayElements(data_, 0);
1104 int dataBufferLength = env->GetArrayLength(data_);
1105
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001106 if (numHeaderElements < MSG_HEADER_SIZE) {
1107 ALOGW("Malformed header len");
1108 return -1;
1109 }
Ashutosh Joshicafdee92016-04-04 16:19:29 -07001110
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001111 uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
1112 uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
1113 int hubHandle = -1;
1114 int hubId;
1115 uint64_t appId;
1116
1117 if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1118 hubHandle = get_hub_handle_for_app_instance(appInstanceHandle);
1119 } else if (msgType == CONTEXT_HUB_LOAD_APP) {
1120 if (numHeaderElements < MSG_HEADER_SIZE_LOAD_APP) {
1121 return -1;
1122 }
1123 uint64_t appIdLo = header[HEADER_FIELD_LOAD_APP_ID_LO];
1124 uint64_t appIdHi = header[HEADER_FIELD_LOAD_APP_ID_HI];
1125 appId = appIdHi << 32 | appIdLo;
1126
1127 hubHandle = header[HEADER_FIELD_HUB_HANDLE];
1128 } else {
1129 hubHandle = header[HEADER_FIELD_HUB_HANDLE];
1130 }
1131
1132 if (hubHandle < 0) {
1133 ALOGD("Invalid hub Handle %d", hubHandle);
1134 return -1;
1135 }
1136
1137 if (msgType == CONTEXT_HUB_LOAD_APP ||
1138 msgType == CONTEXT_HUB_UNLOAD_APP) {
1139
1140 if (isTxnPending()) {
1141 ALOGW("Cannot load or unload app while a transaction is pending !");
1142 return -1;
1143 }
1144
1145 if (msgType == CONTEXT_HUB_LOAD_APP) {
1146 if (startLoadAppTxn(appId, hubHandle) != 0) {
Ashutosh Joshi11864402016-07-15 13:46:22 -07001147 ALOGW("Cannot Start Load Transaction");
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001148 return -1;
1149 }
1150 } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1151 if (startUnloadAppTxn(appInstanceHandle) != 0) {
Ashutosh Joshi11864402016-07-15 13:46:22 -07001152 ALOGW("Cannot Start UnLoad Transaction");
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001153 return -1;
1154 }
1155 }
1156 }
1157
1158 bool setAddressSuccess = false;
1159 hub_message_t msg;
1160
1161 msg.message_type = msgType;
1162
1163 if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1164 msg.message_len = sizeof(db.appInstances[appInstanceHandle].appInfo.app_name);
1165 msg.message = &db.appInstances[appInstanceHandle].appInfo.app_name;
1166 setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
1167 hubId = get_hub_id_for_hub_handle(hubHandle);
1168 } else {
1169 msg.message_len = dataBufferLength;
1170 msg.message = data;
Ashutosh Joshicafdee92016-04-04 16:19:29 -07001171
1172 if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001173 setAddressSuccess = (set_os_app_as_destination(&msg, hubHandle) == 0);
1174 hubId = get_hub_id_for_hub_handle(hubHandle);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001175 } else {
Ashutosh Joshicafdee92016-04-04 16:19:29 -07001176 setAddressSuccess = (set_dest_app(&msg, header[HEADER_FIELD_APP_INSTANCE]) == 0);
1177 hubId = get_hub_id_for_app_instance(header[HEADER_FIELD_APP_INSTANCE]);
1178 }
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001179 }
Ashutosh Joshicafdee92016-04-04 16:19:29 -07001180
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001181 if (setAddressSuccess && hubId >= 0) {
1182 ALOGD("Asking HAL to remove app");
1183 retVal = db.hubInfo.contextHubModule->send_message(hubId, &msg);
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001184 } else {
Greg Kaiserf8210792016-08-18 16:59:12 -07001185 ALOGD("Could not find app instance %" PRId32 " on hubHandle %" PRId32
1186 ", setAddress %d",
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001187 header[HEADER_FIELD_APP_INSTANCE],
1188 header[HEADER_FIELD_HUB_HANDLE],
1189 (int)setAddressSuccess);
1190 }
1191
1192 if (retVal != 0) {
1193 ALOGD("Send Message failure - %d", retVal);
1194 if (msgType == CONTEXT_HUB_LOAD_APP) {
Greg Kaiserca9c6762016-09-07 21:53:57 -07001195 jint ignored;
1196 closeLoadTxn(false, &ignored);
Ashutosh Joshi54787a52016-04-27 11:19:16 -07001197 } else if (msgType == CONTEXT_HUB_UNLOAD_APP) {
1198 closeUnloadTxn(false);
1199 }
Ashutosh Joshib741e3b2016-03-29 09:19:56 -07001200 }
Peng Xu9ff7d222016-02-11 13:02:05 -08001201
1202 env->ReleaseIntArrayElements(header_, header, 0);
1203 env->ReleaseByteArrayElements(data_, data, 0);
1204
1205 return retVal;
1206}
1207
1208//--------------------------------------------------------------------------------------------------
1209//
1210static const JNINativeMethod gContextHubServiceMethods[] = {
1211 {"nativeInitialize",
1212 "()[Landroid/hardware/location/ContextHubInfo;",
1213 (void*)nativeInitialize },
1214 {"nativeSendMessage",
1215 "([I[B)I",
1216 (void*)nativeSendMessage }
1217};
1218
1219}//namespace android
1220
1221using namespace android;
1222
1223int register_android_hardware_location_ContextHubService(JNIEnv *env)
1224{
1225 RegisterMethodsOrDie(env, "android/hardware/location/ContextHubService",
1226 gContextHubServiceMethods, NELEM(gContextHubServiceMethods));
1227
1228 return 0;
1229}