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