blob: 8d10c75121f86822c663b911097729dda229aaae [file] [log] [blame]
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -08001/*
2 * Copyright (C) 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 "Contexthub.h"
18
19#include <inttypes.h>
20
Mark Salyzyn3ff52602017-01-10 10:16:48 -080021#include <log/log.h>
22
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -080023#include <android/hardware/contexthub/1.0/IContexthub.h>
24#include <hardware/context_hub.h>
Brian Duddiec6d2fd42017-01-12 14:47:58 -080025#include <sys/endian.h>
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -080026
27#undef LOG_TAG
28#define LOG_TAG "ContextHubHalAdapter"
29
30namespace android {
31namespace hardware {
32namespace contexthub {
33namespace V1_0 {
34namespace implementation {
35
36static constexpr uint64_t ALL_APPS = UINT64_C(0xFFFFFFFFFFFFFFFF);
37
38Contexthub::Contexthub()
39 : mInitCheck(NO_INIT),
40 mContextHubModule(nullptr),
Brian Duddie154b0882017-06-01 18:51:22 -070041 mDeathRecipient(new DeathRecipient(this)),
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -080042 mIsTransactionPending(false) {
43 const hw_module_t *module;
44
45 mInitCheck = hw_get_module(CONTEXT_HUB_MODULE_ID, &module);
46
47 if (mInitCheck != OK) {
48 ALOGE("Could not load %s module: %s", CONTEXT_HUB_MODULE_ID, strerror(-mInitCheck));
49 } else if (module == nullptr) {
50 ALOGE("hal returned succes but a null module!");
51 // Assign an error, this should not really happen...
52 mInitCheck = UNKNOWN_ERROR;
53 } else {
54 ALOGI("Loaded Context Hub module");
55 mContextHubModule = reinterpret_cast<const context_hub_module_t *>(module);
56 }
57}
58
59bool Contexthub::setOsAppAsDestination(hub_message_t *msg, int hubId) {
60 if (!isValidHubId(hubId)) {
61 ALOGW("%s: Hub information is null for hubHandle %d",
62 __FUNCTION__,
63 hubId);
64 return false;
65 } else {
66 msg->app_name = mCachedHubInfo[hubId].osAppName;
67 return true;
68 }
69}
70
71Return<void> Contexthub::getHubs(getHubs_cb _hidl_cb) {
72 std::vector<ContextHub> hubs;
73 if (isInitialized()) {
74 const context_hub_t *hubArray = nullptr;
75 size_t numHubs;
76
77 // Explicitly discarding const. HAL method discards it.
78 numHubs = mContextHubModule->get_hubs(const_cast<context_hub_module_t *>(mContextHubModule),
79 &hubArray);
80 ALOGI("Context Hub Hal Adapter reports %zu hubs", numHubs);
81
82 mCachedHubInfo.clear();
83
84 for (size_t i = 0; i < numHubs; i++) {
85 CachedHubInformation info;
86 ContextHub c;
87
88 c.hubId = hubArray[i].hub_id;
89 c.name = hubArray[i].name;
90 c.vendor = hubArray[i].vendor;
91 c.toolchain = hubArray[i].toolchain;
92 c.toolchainVersion = hubArray[i].toolchain_version;
93 c.platformVersion = hubArray[i].platform_version;
94 c.maxSupportedMsgLen = hubArray[i].max_supported_msg_len;
95 c.peakMips = hubArray[i].peak_mips;
96 c.peakPowerDrawMw = hubArray[i].peak_power_draw_mw;
97 c.stoppedPowerDrawMw = hubArray[i].stopped_power_draw_mw;
98 c.sleepPowerDrawMw = hubArray[i].sleep_power_draw_mw;
99
Brian Duddie154b0882017-06-01 18:51:22 -0700100 info.callback = nullptr;
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800101 info.osAppName = hubArray[i].os_app_name;
102 mCachedHubInfo[hubArray[i].hub_id] = info;
103
104 hubs.push_back(c);
105 }
106 } else {
107 ALOGW("Context Hub Hal Adapter not initialized");
108 }
109
110 _hidl_cb(hubs);
111 return Void();
112}
113
Brian Duddie154b0882017-06-01 18:51:22 -0700114Contexthub::DeathRecipient::DeathRecipient(sp<Contexthub> contexthub)
115 : mContexthub(contexthub) {}
116
117void Contexthub::DeathRecipient::serviceDied(
118 uint64_t cookie,
119 const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
120 uint32_t hubId = static_cast<uint32_t>(cookie);
121 mContexthub->handleServiceDeath(hubId);
122}
123
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800124bool Contexthub::isValidHubId(uint32_t hubId) {
125 if (!mCachedHubInfo.count(hubId)) {
126 ALOGW("Hub information not found for hubId %" PRIu32, hubId);
127 return false;
128 } else {
129 return true;
130 }
131}
132
133sp<IContexthubCallback> Contexthub::getCallBackForHubId(uint32_t hubId) {
134 if (!isValidHubId(hubId)) {
135 return nullptr;
136 } else {
Brian Duddie154b0882017-06-01 18:51:22 -0700137 return mCachedHubInfo[hubId].callback;
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800138 }
139}
140
141Return<Result> Contexthub::sendMessageToHub(uint32_t hubId,
142 const ContextHubMsg &msg) {
143 if (!isInitialized()) {
144 return Result::NOT_INIT;
145 }
146
147 if (!isValidHubId(hubId) || msg.msg.size() > UINT32_MAX) {
148 return Result::BAD_PARAMS;
149 }
150
151 hub_message_t txMsg = {
152 .app_name.id = msg.appName,
153 .message_type = msg.msgType,
154 .message_len = static_cast<uint32_t>(msg.msg.size()), // Note the check above
155 .message = static_cast<const uint8_t *>(msg.msg.data()),
156 };
157
Arthur Ishiguro28df6402017-11-08 17:45:19 -0800158 // Use a dummy to prevent send_message with empty message from failing prematurely
159 static uint8_t dummy;
160 if (txMsg.message_len == 0 && txMsg.message == nullptr) {
161 txMsg.message = &dummy;
162 }
163
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800164 ALOGI("Sending msg of type %" PRIu32 ", size %" PRIu32 " to app 0x%" PRIx64,
165 txMsg.message_type,
166 txMsg.message_len,
167 txMsg.app_name.id);
168
169 if(mContextHubModule->send_message(hubId, &txMsg) != 0) {
170 return Result::TRANSACTION_FAILED;
171 }
172
173 return Result::OK;
174}
175
176Return<Result> Contexthub::reboot(uint32_t hubId) {
177 if (!isInitialized()) {
178 return Result::NOT_INIT;
179 }
180
181 hub_message_t msg;
182
183 if (setOsAppAsDestination(&msg, hubId) == false) {
184 return Result::BAD_PARAMS;
185 }
186
187 msg.message_type = CONTEXT_HUB_OS_REBOOT;
188 msg.message_len = 0;
189 msg.message = nullptr;
190
191 if(mContextHubModule->send_message(hubId, &msg) != 0) {
192 return Result::TRANSACTION_FAILED;
193 } else {
194 return Result::OK;
195 }
196}
197
198Return<Result> Contexthub::registerCallback(uint32_t hubId,
199 const sp<IContexthubCallback> &cb) {
200 Return<Result> retVal = Result::BAD_PARAMS;
201
202 if (!isInitialized()) {
203 // Not initilalized
204 ALOGW("Context hub not initialized successfully");
205 retVal = Result::NOT_INIT;
206 } else if (!isValidHubId(hubId)) {
207 // Initialized, but hubId is not valid
208 retVal = Result::BAD_PARAMS;
209 } else if (mContextHubModule->subscribe_messages(hubId,
210 contextHubCb,
211 this) == 0) {
212 // Initialized && valid hub && subscription successful
Brian Duddie154b0882017-06-01 18:51:22 -0700213 if (mCachedHubInfo[hubId].callback != nullptr) {
214 ALOGD("Modifying callback for hubId %" PRIu32, hubId);
215 mCachedHubInfo[hubId].callback->unlinkToDeath(mDeathRecipient);
216 }
217
218 mCachedHubInfo[hubId].callback = cb;
219 if (cb != nullptr) {
220 Return<bool> linkResult = cb->linkToDeath(mDeathRecipient, hubId);
221 bool linkSuccess = linkResult.isOk() ?
222 static_cast<bool>(linkResult) : false;
223 if (!linkSuccess) {
224 ALOGW("Couldn't link death recipient for hubId %" PRIu32,
225 hubId);
226 }
227 }
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800228 retVal = Result::OK;
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800229 } else {
230 // Initalized && valid hubId - but subscription unsuccessful
231 // This is likely an internal error in the HAL implementation, but we
232 // cannot add more information.
233 ALOGW("Could not subscribe to the hub for callback");
234 retVal = Result::UNKNOWN_FAILURE;
235 }
236
237 return retVal;
238}
239
240static bool isValidOsStatus(const uint8_t *msg,
241 size_t msgLen,
242 status_response_t *rsp) {
243 // Workaround a bug in some HALs
244 if (msgLen == 1) {
245 rsp->result = msg[0];
246 return true;
247 }
248
249 if (msg == nullptr || msgLen != sizeof(*rsp)) {
250 ALOGI("Received invalid response (is null : %d, size %zu)",
251 msg == nullptr ? 1 : 0,
252 msgLen);
253 return false;
254 }
255
256 memcpy(rsp, msg, sizeof(*rsp));
257
258 // No sanity checks on return values
259 return true;
260}
261
262int Contexthub::handleOsMessage(sp<IContexthubCallback> cb,
263 uint32_t msgType,
264 const uint8_t *msg,
265 int msgLen) {
266 int retVal = -1;
267
268
269 switch(msgType) {
270 case CONTEXT_HUB_APPS_ENABLE:
271 case CONTEXT_HUB_APPS_DISABLE:
272 case CONTEXT_HUB_LOAD_APP:
273 case CONTEXT_HUB_UNLOAD_APP:
274 {
275 struct status_response_t rsp;
276 TransactionResult result;
277 if (isValidOsStatus(msg, msgLen, &rsp) && rsp.result == 0) {
278 retVal = 0;
279 result = TransactionResult::SUCCESS;
280 } else {
281 result = TransactionResult::FAILURE;
282 }
283
284 if (cb != nullptr) {
285 cb->handleTxnResult(mTransactionId, result);
286 }
287 retVal = 0;
288 mIsTransactionPending = false;
289 break;
290 }
291
292 case CONTEXT_HUB_QUERY_APPS:
293 {
294 std::vector<HubAppInfo> apps;
295 int numApps = msgLen / sizeof(hub_app_info);
296 const hub_app_info *unalignedInfoAddr = reinterpret_cast<const hub_app_info *>(msg);
297
298 for (int i = 0; i < numApps; i++) {
299 hub_app_info query_info;
300 memcpy(&query_info, &unalignedInfoAddr[i], sizeof(query_info));
301 HubAppInfo app;
302 app.appId = query_info.app_name.id;
303 app.version = query_info.version;
304 // TODO :: Add memory ranges
305
306 apps.push_back(app);
307 }
308
309 if (cb != nullptr) {
310 cb->handleAppsInfo(apps);
311 }
312 retVal = 0;
313 break;
314 }
315
316 case CONTEXT_HUB_QUERY_MEMORY:
317 {
318 // Deferring this use
319 retVal = 0;
320 break;
321 }
322
323 case CONTEXT_HUB_OS_REBOOT:
324 {
325 mIsTransactionPending = false;
326 if (cb != nullptr) {
327 cb->handleHubEvent(AsyncEventType::RESTARTED);
328 }
329 retVal = 0;
330 break;
331 }
332
333 default:
334 {
335 retVal = -1;
336 break;
337 }
338 }
339
340 return retVal;
341}
342
Brian Duddie154b0882017-06-01 18:51:22 -0700343void Contexthub::handleServiceDeath(uint32_t hubId) {
344 ALOGI("Callback/service died for hubId %" PRIu32, hubId);
345 int ret = mContextHubModule->subscribe_messages(hubId, nullptr, nullptr);
346 if (ret != 0) {
347 ALOGW("Failed to unregister callback from hubId %" PRIu32 ": %d",
348 hubId, ret);
349 }
350 mCachedHubInfo[hubId].callback.clear();
351}
352
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800353int Contexthub::contextHubCb(uint32_t hubId,
354 const struct hub_message_t *rxMsg,
355 void *cookie) {
356 Contexthub *obj = static_cast<Contexthub *>(cookie);
357
358 if (rxMsg == nullptr) {
359 ALOGW("Ignoring NULL message");
360 return -1;
361 }
362
363 if (!obj->isValidHubId(hubId)) {
364 ALOGW("Invalid hub Id %" PRIu32, hubId);
365 return -1;
366 }
367
368 sp<IContexthubCallback> cb = obj->getCallBackForHubId(hubId);
369
370 if (cb == nullptr) {
371 // This should not ever happen
372 ALOGW("No callback registered, returning");
373 return -1;
374 }
375
376 if (rxMsg->message_type < CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE) {
377 obj->handleOsMessage(cb,
378 rxMsg->message_type,
379 static_cast<const uint8_t *>(rxMsg->message),
380 rxMsg->message_len);
381 } else {
382 ContextHubMsg msg;
383
384 msg.appName = rxMsg->app_name.id;
385 msg.msgType = rxMsg->message_type;
386 msg.msg = std::vector<uint8_t>(static_cast<const uint8_t *>(rxMsg->message),
387 static_cast<const uint8_t *>(rxMsg->message) +
388 rxMsg->message_len);
389
390 cb->handleClientMsg(msg);
391 }
392
393 return 0;
394}
395
396Return<Result> Contexthub::unloadNanoApp(uint32_t hubId,
397 uint64_t appId,
398 uint32_t transactionId) {
399 if (!isInitialized()) {
400 return Result::NOT_INIT;
401 }
402
403 if (mIsTransactionPending) {
404 return Result::TRANSACTION_PENDING;
405 }
406
407 hub_message_t msg;
408
409 if (setOsAppAsDestination(&msg, hubId) == false) {
410 return Result::BAD_PARAMS;
411 }
412
413 struct apps_disable_request_t req;
414
415 msg.message_type = CONTEXT_HUB_UNLOAD_APP;
416 msg.message_len = sizeof(req);
417 msg.message = &req;
418 req.app_name.id = appId;
419
420 if(mContextHubModule->send_message(hubId, &msg) != 0) {
421 return Result::TRANSACTION_FAILED;
422 } else {
423 mTransactionId = transactionId;
424 mIsTransactionPending = true;
425 return Result::OK;
426 }
427}
428
429Return<Result> Contexthub::loadNanoApp(uint32_t hubId,
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800430 const NanoAppBinary& appBinary,
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800431 uint32_t transactionId) {
432 if (!isInitialized()) {
433 return Result::NOT_INIT;
434 }
435
436 if (mIsTransactionPending) {
437 return Result::TRANSACTION_PENDING;
438 }
439
440 hub_message_t hubMsg;
441
442 if (setOsAppAsDestination(&hubMsg, hubId) == false) {
443 return Result::BAD_PARAMS;
444 }
445
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800446 // Data from the nanoapp header is passed through HIDL as explicit fields,
447 // but the legacy HAL expects it prepended to the binary, therefore we must
448 // reconstruct it here prior to passing to the legacy HAL.
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800449 const struct nano_app_binary_t header = {
450 .header_version = htole32(1),
Brian Duddiea2d49d12017-08-18 17:57:00 -0700451 .magic = htole32(NANOAPP_MAGIC),
452 .app_id.id = htole64(appBinary.appId),
453 .app_version = htole32(appBinary.appVersion),
454 .flags = htole32(appBinary.flags),
455 .hw_hub_type = htole64(0),
456 .target_chre_api_major_version = appBinary.targetChreApiMajorVersion,
457 .target_chre_api_minor_version = appBinary.targetChreApiMinorVersion,
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800458 };
459 const uint8_t *headerBytes = reinterpret_cast<const uint8_t *>(&header);
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800460
Brian Duddiec6d2fd42017-01-12 14:47:58 -0800461 std::vector<uint8_t> binaryWithHeader(appBinary.customBinary);
462 binaryWithHeader.insert(binaryWithHeader.begin(),
463 headerBytes,
464 headerBytes + sizeof(header));
465
466 hubMsg.message_type = CONTEXT_HUB_LOAD_APP;
467 hubMsg.message_len = binaryWithHeader.size();
468 hubMsg.message = binaryWithHeader.data();
469
470 if (mContextHubModule->send_message(hubId, &hubMsg) != 0) {
Ashutosh Joshi1bec86a2016-11-15 13:48:58 -0800471 return Result::TRANSACTION_FAILED;
472 } else {
473 mTransactionId = transactionId;
474 mIsTransactionPending = true;
475 return Result::OK;
476 }
477}
478
479Return<Result> Contexthub::enableNanoApp(uint32_t hubId,
480 uint64_t appId,
481 uint32_t transactionId) {
482 if (!isInitialized()) {
483 return Result::NOT_INIT;
484 }
485
486 if (mIsTransactionPending) {
487 return Result::TRANSACTION_PENDING;
488 }
489
490 hub_message_t msg;
491
492 if (setOsAppAsDestination(&msg, hubId) == false) {
493 return Result::BAD_PARAMS;
494 }
495
496 struct apps_enable_request_t req;
497
498 msg.message_type = CONTEXT_HUB_APPS_ENABLE;
499 msg.message_len = sizeof(req);
500 req.app_name.id = appId;
501 msg.message = &req;
502
503 if(mContextHubModule->send_message(hubId, &msg) != 0) {
504 return Result::TRANSACTION_FAILED;
505 } else {
506 mTransactionId = transactionId;
507 mIsTransactionPending = true;
508 return Result::OK;
509 }
510}
511
512Return<Result> Contexthub::disableNanoApp(uint32_t hubId,
513 uint64_t appId,
514 uint32_t transactionId) {
515 if (!isInitialized()) {
516 return Result::NOT_INIT;
517 }
518
519 if (mIsTransactionPending) {
520 return Result::TRANSACTION_PENDING;
521 }
522
523 hub_message_t msg;
524
525 if (setOsAppAsDestination(&msg, hubId) == false) {
526 return Result::BAD_PARAMS;
527 }
528
529 struct apps_disable_request_t req;
530
531 msg.message_type = CONTEXT_HUB_APPS_DISABLE;
532 msg.message_len = sizeof(req);
533 req.app_name.id = appId;
534 msg.message = &req;
535
536 if(mContextHubModule->send_message(hubId, &msg) != 0) {
537 return Result::TRANSACTION_FAILED;
538 } else {
539 mTransactionId = transactionId;
540 mIsTransactionPending = true;
541 return Result::OK;
542 }
543}
544
545Return<Result> Contexthub::queryApps(uint32_t hubId) {
546 if (!isInitialized()) {
547 return Result::NOT_INIT;
548 }
549
550 hub_message_t msg;
551
552 if (setOsAppAsDestination(&msg, hubId) == false) {
553 ALOGW("Could not find hubId %" PRIu32, hubId);
554 return Result::BAD_PARAMS;
555 }
556
557 query_apps_request_t payload;
558 payload.app_name.id = ALL_APPS; // TODO : Pass this in as a parameter
559 msg.message = &payload;
560 msg.message_len = sizeof(payload);
561 msg.message_type = CONTEXT_HUB_QUERY_APPS;
562
563 if(mContextHubModule->send_message(hubId, &msg) != 0) {
564 ALOGW("Query Apps sendMessage failed");
565 return Result::TRANSACTION_FAILED;
566 }
567
568 return Result::OK;
569}
570
571bool Contexthub::isInitialized() {
572 return (mInitCheck == OK && mContextHubModule != nullptr);
573}
574
575IContexthub *HIDL_FETCH_IContexthub(const char * halName) {
576 ALOGI("%s Called for %s", __FUNCTION__, halName);
577 Contexthub *contexthub = new Contexthub;
578
579 if (!contexthub->isInitialized()) {
580 delete contexthub;
581 contexthub = nullptr;
582 }
583
584 return contexthub;
585}
586
587} // namespace implementation
588} // namespace V1_0
589} // namespace contexthub
590} // namespace hardware
591} // namespace android