1/*
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#define LOG_TAG "NanohubHAL"
18
19#include "file.h"
20#include <json/json.h>
21
22#include <cassert>
23#include <cerrno>
24#include <cinttypes>
25#include <string>
26
27#include <endian.h>
28
29#include <vector>
30
31#include <log/log.h>
32
33#include <endian.h>
34#include <sys/stat.h>
35
36#include <media/stagefright/foundation/ADebug.h>
37
38#include <hardware/context_hub.h>
39#include "nanohub_perdevice.h"
40#include "system_comms.h"
41#include "nanohubhal.h"
42
43#define CHRE_APP_DIR        "/data/vendor/sensor/chre"
44#define CHRE_APP_DIR_PERMS  (S_IRUSR | S_IWUSR | S_IXUSR)
45#define CHRE_APP_FILE_PERMS (S_IRUSR | S_IWUSR)
46#define CHRE_APP_SETTINGS   CHRE_APP_DIR "/apps.json"
47
48namespace android {
49
50namespace nanohub {
51
52static void readAppName(MessageBuf &buf, hub_app_name_t &name)
53{
54    name.id = buf.readU64();
55}
56
57static void writeAppName(MessageBuf &buf, const hub_app_name_t &name)
58{
59    buf.writeU64(name.id);
60}
61
62static void readNanohubMemInfo(MessageBuf &buf, NanohubMemInfo &mi)
63{
64    uint8_t type, len;
65    uint32_t ramFree = NANOHUB_MEM_SZ_UNKNOWN;
66    uint32_t eeFree = NANOHUB_MEM_SZ_UNKNOWN;
67    uint32_t sharedFree = NANOHUB_MEM_SZ_UNKNOWN;
68    uint32_t osFree = NANOHUB_MEM_SZ_UNKNOWN;
69
70    mi.flashSz = NANOHUB_MEM_SZ_UNKNOWN;
71    mi.blSz = NANOHUB_MEM_SZ_UNKNOWN;
72    mi.osSz = NANOHUB_MEM_SZ_UNKNOWN;
73    mi.sharedSz = NANOHUB_MEM_SZ_UNKNOWN;
74    mi.eeSz = NANOHUB_MEM_SZ_UNKNOWN;
75    mi.ramSz = NANOHUB_MEM_SZ_UNKNOWN;
76
77    mi.blUse = NANOHUB_MEM_SZ_UNKNOWN;
78    mi.osUse = NANOHUB_MEM_SZ_UNKNOWN;
79    mi.sharedUse = NANOHUB_MEM_SZ_UNKNOWN;
80    mi.eeUse = NANOHUB_MEM_SZ_UNKNOWN;
81    mi.ramUse = NANOHUB_MEM_SZ_UNKNOWN;
82
83    while (buf.getRoom() >= 2) {
84        type = buf.readU8();
85        len = buf.readU8();
86        if (buf.getRoom() >= len) {
87            switch(type) {
88            case NANOHUB_HAL_SYS_INFO_HEAP_FREE:
89                if (len == sizeof(ramFree))
90                    ramFree = buf.readU32();
91                else
92                    buf.readRaw(len);
93                break;
94            case NANOHUB_HAL_SYS_INFO_RAM_SIZE:
95                if (len == sizeof(mi.ramSz))
96                    mi.ramSz = buf.readU32();
97                else
98                    buf.readRaw(len);
99                break;
100            case NANOHUB_HAL_SYS_INFO_EEDATA_SIZE:
101                if (len == sizeof(mi.ramSz))
102                    mi.eeSz = buf.readU32();
103                else
104                    buf.readRaw(len);
105                break;
106            case NANOHUB_HAL_SYS_INFO_EEDATA_FREE:
107                if (len == sizeof(eeFree))
108                    eeFree = buf.readU32();
109                else
110                    buf.readRaw(len);
111                break;
112            case NANOHUB_HAL_SYS_INFO_CODE_SIZE:
113                if (len == sizeof(mi.osSz))
114                    mi.osSz = buf.readU32();
115                else
116                    buf.readRaw(len);
117                break;
118            case NANOHUB_HAL_SYS_INFO_CODE_FREE:
119                if (len == sizeof(osFree))
120                    osFree = buf.readU32();
121                else
122                    buf.readRaw(len);
123                break;
124            case NANOHUB_HAL_SYS_INFO_SHARED_SIZE:
125                if (len == sizeof(mi.sharedSz))
126                    mi.sharedSz = buf.readU32();
127                else
128                    buf.readRaw(len);
129                break;
130            case NANOHUB_HAL_SYS_INFO_SHARED_FREE:
131                if (len == sizeof(sharedFree))
132                    sharedFree = buf.readU32();
133                else
134                    buf.readRaw(len);
135                break;
136            case NANOHUB_HAL_SYS_INFO_END:
137                if (len != 0 || buf.getRoom() != 0) {
138                    ALOGE("%s: failed to read object", __func__);
139                    return;
140                }
141                break;
142            default:
143                ALOGI("%s: unsupported type: %d", __func__, type);
144                buf.readRaw(len);
145                break;
146            }
147        } else {
148            ALOGE("%s: failed to read object", __func__);
149            return;
150        }
151    }
152
153    if (buf.getRoom() != 0) {
154        ALOGE("%s: failed to read object", __func__);
155        return;
156    }
157
158    if (mi.ramSz != NANOHUB_MEM_SZ_UNKNOWN && ramFree != NANOHUB_MEM_SZ_UNKNOWN)
159        mi.ramUse = mi.ramSz - ramFree;
160    if (mi.eeSz != NANOHUB_MEM_SZ_UNKNOWN && eeFree != NANOHUB_MEM_SZ_UNKNOWN)
161        mi.eeUse = mi.eeSz - eeFree;
162    if (mi.osSz != NANOHUB_MEM_SZ_UNKNOWN && osFree != NANOHUB_MEM_SZ_UNKNOWN)
163        mi.osUse = mi.osSz - osFree;
164    if (mi.sharedSz != NANOHUB_MEM_SZ_UNKNOWN && sharedFree != NANOHUB_MEM_SZ_UNKNOWN)
165        mi.sharedUse = mi.sharedSz - sharedFree;
166}
167
168NanohubRsp::NanohubRsp(MessageBuf &buf, uint32_t transactionId, bool chre)
169{
170    // all responses start with command and have a 4-byte status (result code)
171    buf.reset();
172    if (buf.getSize() < 5) {
173        mStatus = -EINVAL;
174    } else {
175        mCmd = buf.readU8();
176        mStatus = buf.readU32();
177        if (chre)
178            mTransactionId = transactionId;
179        else
180            mTransactionId = 0;
181    }
182}
183
184int SystemComm::sendToSystem(const void *data, size_t len, uint32_t transactionId)
185{
186    if (NanoHub::messageTracingEnabled()) {
187        dumpBuffer("HAL -> SYS", getSystem()->mHostIfAppName, transactionId, 0, data, len);
188    }
189    return NanoHub::sendToDevice(&getSystem()->mHostIfAppName, data, len, transactionId);
190}
191
192inline hub_app_name_t deviceAppNameToHost(const hub_app_name_t src)
193{
194    hub_app_name_t res = { .id = le64toh(src.id) };
195    return res;
196}
197
198inline hub_app_name_t hostAppNameToDevice(const hub_app_name_t src)
199{
200    hub_app_name_t res = { .id = htole64(src.id) };
201    return res;
202}
203
204const uint8_t app_info_tags[] =
205{
206    NANOHUB_HAL_APP_INFO_APPID,
207    NANOHUB_HAL_APP_INFO_CRC,
208    NANOHUB_HAL_APP_INFO_TID,
209    NANOHUB_HAL_APP_INFO_VERSION,
210    NANOHUB_HAL_APP_INFO_ADDR,
211    NANOHUB_HAL_APP_INFO_SIZE,
212    NANOHUB_HAL_APP_INFO_HEAP,
213    NANOHUB_HAL_APP_INFO_DATA,
214    NANOHUB_HAL_APP_INFO_BSS,
215    NANOHUB_HAL_APP_INFO_CHRE_MAJOR,
216    NANOHUB_HAL_APP_INFO_CHRE_MINOR,
217    NANOHUB_HAL_APP_INFO_END,
218};
219
220const uint8_t sys_info_tags[] =
221{
222    NANOHUB_HAL_SYS_INFO_HEAP_FREE,
223    NANOHUB_HAL_SYS_INFO_RAM_SIZE,
224    NANOHUB_HAL_SYS_INFO_EEDATA_SIZE,
225    NANOHUB_HAL_SYS_INFO_EEDATA_FREE,
226    NANOHUB_HAL_SYS_INFO_CODE_SIZE,
227    NANOHUB_HAL_SYS_INFO_CODE_FREE,
228    NANOHUB_HAL_SYS_INFO_SHARED_SIZE,
229    NANOHUB_HAL_SYS_INFO_SHARED_FREE,
230    NANOHUB_HAL_SYS_INFO_END,
231};
232
233int SystemComm::MemInfoSession::setup(const hub_message_t *, uint32_t transactionId, AppManager &)
234{
235    std::lock_guard<std::mutex> _l(mLock);
236    char data[MAX_RX_PACKET];
237    MessageBuf buf(data, sizeof(data));
238    buf.writeU8(NANOHUB_HAL_SYS_INFO);
239    buf.writeRaw(sys_info_tags, sizeof(sys_info_tags));
240
241    setState(SESSION_USER);
242    return sendToSystem(buf.getData(), buf.getPos(), transactionId);
243}
244
245int SystemComm::MemInfoSession::handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &, bool chre)
246{
247    std::lock_guard<std::mutex> _l(mLock);
248    NanohubRsp rsp(buf, transactionId, chre);
249
250    if (rsp.mCmd != NANOHUB_HAL_SYS_INFO)
251        return 1;
252
253    size_t len = buf.getRoom();
254
255    if (getState() != SESSION_USER) {
256        ALOGE("%s: Invalid state; have %d, need %d", __func__, getState(), SESSION_USER);
257        return -EINVAL;
258    }
259
260    std::vector<mem_range_t> ranges;
261    ranges.reserve(4);
262    if (len) {
263        NanohubMemInfo mi;
264        readNanohubMemInfo(buf, mi);
265
266        //if each is valid, copy to output area
267        if (mi.sharedSz != NANOHUB_MEM_SZ_UNKNOWN &&
268            mi.sharedUse != NANOHUB_MEM_SZ_UNKNOWN)
269            ranges.push_back({
270                .type = HUB_MEM_TYPE_MAIN,
271                .total_bytes = mi.sharedSz,
272                .free_bytes = mi.sharedSz - mi.sharedUse,
273            });
274
275        if (mi.osSz != NANOHUB_MEM_SZ_UNKNOWN &&
276            mi.osUse != NANOHUB_MEM_SZ_UNKNOWN)
277            ranges.push_back({
278                .type = HUB_MEM_TYPE_OS,
279                .total_bytes = mi.osSz,
280                .free_bytes = mi.osSz - mi.osUse,
281            });
282
283        if (mi.eeSz != NANOHUB_MEM_SZ_UNKNOWN &&
284            mi.eeUse != NANOHUB_MEM_SZ_UNKNOWN)
285            ranges.push_back({
286                .type = HUB_MEM_TYPE_EEDATA,
287                .total_bytes = mi.eeSz,
288                .free_bytes = mi.eeSz - mi.eeUse,
289            });
290
291        if (mi.ramSz != NANOHUB_MEM_SZ_UNKNOWN &&
292            mi.ramUse != NANOHUB_MEM_SZ_UNKNOWN)
293            ranges.push_back({
294                .type = HUB_MEM_TYPE_RAM,
295                .total_bytes = mi.ramSz,
296                .free_bytes = mi.ramSz - mi.ramUse,
297            });
298    }
299
300    //send it out
301    sendToApp(CONTEXT_HUB_QUERY_MEMORY, transactionId,
302              static_cast<const void *>(ranges.data()),
303              ranges.size() * sizeof(ranges[0]));
304
305    complete();
306    return 0;
307}
308
309int SystemComm::AppMgmtSession::setup(const hub_message_t *appMsg, uint32_t transactionId, AppManager &appManager)
310{
311    std::lock_guard<std::mutex> _l(mLock);
312
313    char data[MAX_RX_PACKET];
314    MessageBuf buf(data, sizeof(data));
315    const uint8_t *msgData = static_cast<const uint8_t*>(appMsg->message);
316
317    mCmd = appMsg->message_type;
318    mLen = appMsg->message_len;
319    mPos = 0;
320    mNextPos = 0;
321    mErrCnt = 0;
322
323    switch (mCmd) {
324    case  CONTEXT_HUB_APPS_ENABLE:
325        return setupMgmt(appMsg, transactionId, NANOHUB_HAL_APP_MGMT_START, appManager);
326    case  CONTEXT_HUB_APPS_DISABLE:
327        return setupMgmt(appMsg, transactionId, NANOHUB_HAL_APP_MGMT_STOP, appManager);
328    case  CONTEXT_HUB_UNLOAD_APP:
329        return setupMgmt(appMsg, transactionId, NANOHUB_HAL_APP_MGMT_UNLOAD, appManager);
330    case  CONTEXT_HUB_LOAD_APP:
331    {
332        const load_app_request_t *appReq = static_cast<const load_app_request_t*>(appMsg->message);
333        if (appReq == nullptr || mLen <= sizeof(*appReq)) {
334            ALOGE("%s: Invalid app header: too short\n", __func__);
335            return -EINVAL;
336        }
337        mAppName = appReq->app_binary.app_id;
338        if (!appManager.isAppLoaded(mAppName)) {
339            appManager.addNewApp(mAppName, appReq->app_binary.app_version);
340            appManager.writeApp(mAppName, msgData, mLen);
341            mData.clear();
342            mData = std::vector<uint8_t>(msgData, msgData + mLen);
343            setState(TRANSFER);
344
345            buf.writeU8(NANOHUB_HAL_START_UPLOAD);
346            buf.writeU8(0);
347            buf.writeU32(mLen);
348
349            return sendToSystem(buf.getData(), buf.getPos(), transactionId);
350        } else {
351            if (appManager.cmpApp(mAppName, msgData, mLen)) {
352                mFlashAddr = appManager.getFlashAddr(mAppName);
353                if (appManager.isAppRunning(mAppName)) {
354                    setState(STOP_RUN);
355
356                    buf.writeU8(NANOHUB_HAL_APP_MGMT);
357                    writeAppName(buf, mAppName);
358                    buf.writeU8(NANOHUB_HAL_APP_MGMT_STOP);
359
360                    return sendToSystem(buf.getData(), buf.getPos(), transactionId);
361                } else {
362                    setState(RUN);
363
364                    buf.writeU8(NANOHUB_HAL_APP_MGMT);
365                    writeAppName(buf, mAppName);
366                    buf.writeU8(NANOHUB_HAL_APP_MGMT_START);
367
368                    return sendToSystem(buf.getData(), buf.getPos(), transactionId);
369                }
370            } else {
371                appManager.setCachedVersion(mAppName, appReq->app_binary.app_version);
372                appManager.writeApp(mAppName, msgData, mLen);
373                mData.clear();
374                mData = std::vector<uint8_t>(msgData, msgData + mLen);
375                if (appManager.isAppRunning(mAppName)) {
376                    setState(STOP_TRANSFER);
377
378                    buf.writeU8(NANOHUB_HAL_APP_MGMT);
379                    writeAppName(buf, mAppName);
380                    buf.writeU8(NANOHUB_HAL_APP_MGMT_STOP);
381
382                    return sendToSystem(buf.getData(), buf.getPos(), transactionId);
383                } else {
384                    setState(TRANSFER);
385
386                    buf.writeU8(NANOHUB_HAL_START_UPLOAD);
387                    buf.writeU8(0);
388                    buf.writeU32(mLen);
389
390                    return sendToSystem(buf.getData(), buf.getPos(), transactionId);
391                }
392            }
393        }
394    }
395    case  CONTEXT_HUB_OS_REBOOT:
396        setState(REBOOT);
397
398        buf.writeU8(NANOHUB_HAL_SYS_MGMT);
399        buf.writeU8(NANOHUB_HAL_SYS_MGMT_REBOOT);
400
401        return sendToSystem(buf.getData(), buf.getPos(), transactionId);
402
403    case  CONTEXT_HUB_START_APPS:
404        if (mLen == sizeof(mStatus))
405            memcpy(&mStatus, msgData, mLen);
406        appManager.eraseApps();
407        setState(QUERY_START);
408
409        buf.writeU8(NANOHUB_HAL_APP_INFO);
410        buf.writeU32(0);
411        buf.writeRaw(app_info_tags, sizeof(app_info_tags));
412
413        return sendToSystem(buf.getData(), buf.getPos(), transactionId);
414    }
415
416    return -EINVAL;
417}
418
419int SystemComm::AppMgmtSession::setupMgmt(const hub_message_t *appMsg, uint32_t transactionId, uint32_t cmd, AppManager &appManager)
420{
421    int32_t result = 0;
422    const hub_app_name_t &appName = *static_cast<const hub_app_name_t*>(appMsg->message);
423    if (appMsg->message_len != sizeof(appName)) {
424        return -EINVAL;
425    }
426    mAppName = appName;
427
428    switch (cmd) {
429    case NANOHUB_HAL_APP_MGMT_START:
430        if (appManager.isAppRunning(mAppName)) {
431            appManager.setCachedStart(mAppName, true);
432            sendToApp(mCmd, transactionId, &result, sizeof(result));
433            complete();
434            return 0;
435        }
436        break;
437    case NANOHUB_HAL_APP_MGMT_STOP:
438    case NANOHUB_HAL_APP_MGMT_UNLOAD:
439        appManager.setCachedStart(mAppName, false);
440        if (!appManager.isAppRunning(mAppName)) {
441            sendToApp(mCmd, transactionId, &result, sizeof(result));
442            complete();
443            return 0;
444        }
445        break;
446    }
447    char data[MAX_RX_PACKET];
448    MessageBuf buf(data, sizeof(data));
449    buf.writeU8(NANOHUB_HAL_APP_MGMT);
450    writeAppName(buf, appName);
451    buf.writeU8(cmd);
452    setState(MGMT);
453
454    return sendToSystem(buf.getData(), buf.getPos(), transactionId);
455}
456
457int SystemComm::AppMgmtSession::handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre)
458{
459    int ret = 0;
460    std::lock_guard<std::mutex> _l(mLock);
461    NanohubRsp rsp(buf, transactionId, chre);
462
463    switch (getState()) {
464    case TRANSFER:
465        ret = handleTransfer(rsp, buf, appManager);
466        break;
467    case STOP_TRANSFER:
468        ret = handleStopTransfer(rsp, buf, appManager);
469         break;
470    case QUERY_START:
471        ret = handleQueryStart(rsp, buf, appManager);
472        break;
473    case START:
474        ret = handleStart(rsp, buf, appManager);
475        break;
476    case FINISH:
477        ret = handleFinish(rsp, buf, appManager);
478        break;
479    case RUN:
480        ret = handleRun(rsp, buf, appManager);
481        break;
482    case STOP_RUN:
483        ret = handleStopRun(rsp, buf, appManager);
484        break;
485    case REBOOT:
486        ret = handleReboot(rsp, buf, appManager);
487        break;
488    case ERASE_TRANSFER:
489        ret = handleEraseTransfer(rsp, buf, appManager);
490        break;
491    case MGMT:
492        ret = handleMgmt(rsp, buf, appManager);
493        break;
494    case INFO:
495        ret = handleInfo(rsp, buf, appManager);
496        break;
497    }
498
499    return ret;
500}
501
502int SystemComm::AppMgmtSession::handleTransfer(NanohubRsp &rsp, MessageBuf &, AppManager &appManager)
503{
504    if (rsp.mCmd != NANOHUB_HAL_CONT_UPLOAD && rsp.mCmd != NANOHUB_HAL_START_UPLOAD)
505        return 1;
506
507    char data[MAX_RX_PACKET];
508    MessageBuf buf(data, sizeof(data));
509    int32_t result = 0;
510
511    static_assert(NANOHUB_UPLOAD_CHUNK_SZ_MAX <= (MAX_RX_PACKET-5),
512                  "Invalid chunk size");
513
514    if (rsp.mStatus == NANOHUB_HAL_UPLOAD_ACCEPTED) {
515        mPos = mNextPos;
516        mErrCnt = 0;
517    } else if (rsp.mStatus == NANOHUB_HAL_UPLOAD_RESEND) {
518        mErrCnt ++;
519    } else if (rsp.mStatus == NANOHUB_HAL_UPLOAD_RESTART) {
520        mPos = 0;
521        mErrCnt ++;
522    } else if (rsp.mStatus == NANOHUB_HAL_UPLOAD_CANCEL ||
523               rsp.mStatus == NANOHUB_HAL_UPLOAD_CANCEL_NO_RETRY) {
524        mPos = mLen;
525        result = NANOHUB_APP_NOT_LOADED;
526    } else if (rsp.mStatus == NANOHUB_HAL_UPLOAD_NO_SPACE) {
527        mPos = 0;
528        mErrCnt = 0;
529        setState(ERASE_TRANSFER);
530
531        buf.writeU8(NANOHUB_HAL_SYS_MGMT);
532        buf.writeU8(NANOHUB_HAL_SYS_MGMT_ERASE);
533
534        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
535    } else if (mErrCnt > 5) {
536        mPos = mLen;
537        result = NANOHUB_APP_NOT_LOADED;
538    } else {
539        mErrCnt ++;
540    }
541
542    if (result != 0) {
543        appManager.clearCachedApp(mAppName);
544
545        sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
546        complete();
547        return 0;
548    } else if (mPos < mLen) {
549        uint32_t chunkSize = mLen - mPos;
550
551        if (chunkSize > NANOHUB_UPLOAD_CHUNK_SZ_MAX) {
552            chunkSize = NANOHUB_UPLOAD_CHUNK_SZ_MAX;
553        }
554
555        buf.writeU8(NANOHUB_HAL_CONT_UPLOAD);
556        buf.writeU32(mPos);
557        buf.writeRaw(&mData[mPos], chunkSize);
558        mNextPos = mPos + chunkSize;
559    } else {
560        buf.writeU8(NANOHUB_HAL_FINISH_UPLOAD);
561        setState(FINISH);
562    }
563
564    return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
565}
566
567int SystemComm::AppMgmtSession::handleStopTransfer(NanohubRsp &rsp, MessageBuf &buf, AppManager &)
568{
569    if (rsp.mCmd != NANOHUB_HAL_APP_MGMT)
570        return 1;
571
572    uint8_t cmd = buf.readU8();
573
574    if (cmd != NANOHUB_HAL_APP_MGMT_STOP)
575        return 1;
576
577    MgmtStatus sts = { .value = buf.readU32() };
578
579    ALOGI("Nanohub NEW APP STOP: %08" PRIX32 "\n", sts.value);
580    if (rsp.mStatus == 0) {
581        char data[MAX_RX_PACKET];
582        MessageBuf buf(data, sizeof(data));
583        setState(TRANSFER);
584
585        buf.writeU8(NANOHUB_HAL_START_UPLOAD);
586        buf.writeU8(0);
587        buf.writeU32(mLen);
588        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
589    } else {
590        int32_t result = NANOHUB_APP_NOT_LOADED;
591
592        sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
593        complete();
594        return 0;
595    }
596}
597
598int SystemComm::AppMgmtSession::handleQueryStart(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager)
599{
600
601    if (rsp.mCmd != NANOHUB_HAL_APP_INFO)
602        return 1;
603
604    size_t len = buf.getRoom();
605    if (len) {
606        uint32_t nextAddr = appManager.readNanohubAppInfo(buf);
607
608        if (nextAddr) {
609            char data[MAX_RX_PACKET];
610            MessageBuf buf(data, sizeof(data));
611
612            buf.writeU8(NANOHUB_HAL_APP_INFO);
613            buf.writeU32(nextAddr);
614            buf.writeRaw(app_info_tags, sizeof(app_info_tags));
615
616            return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
617        }
618    }
619
620    appManager.getAppsToStart(mAppList);
621    if (mAppList.empty()) {
622        sendToApp(CONTEXT_HUB_OS_REBOOT, 0, &mStatus, sizeof(mStatus));
623        complete();
624        return 0;
625    } else {
626        char data[MAX_RX_PACKET];
627        MessageBuf buf(data, sizeof(data));
628        mAppName = mAppList.back();
629        mAppList.pop_back();
630        setState(START);
631
632        buf.writeU8(NANOHUB_HAL_APP_MGMT);
633        writeAppName(buf, mAppName);
634        buf.writeU8(NANOHUB_HAL_APP_MGMT_START);
635        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
636    }
637}
638
639int SystemComm::AppMgmtSession::handleStart(NanohubRsp &rsp, MessageBuf &buf, AppManager &)
640{
641    if (rsp.mCmd != NANOHUB_HAL_APP_MGMT)
642        return 1;
643
644    uint8_t cmd = buf.readU8();
645
646    if (cmd != NANOHUB_HAL_APP_MGMT_START)
647        return 1;
648
649    MgmtStatus sts = { .value = buf.readU32() };
650
651    ALOGI("Nanohub EXISTING APP START: %08" PRIX32 "\n", sts.value);
652    if (mAppList.empty()) {
653        sendToApp(CONTEXT_HUB_OS_REBOOT, 0, &mStatus, sizeof(mStatus));
654        complete();
655        return 0;
656    } else {
657        char data[MAX_RX_PACKET];
658        MessageBuf buf(data, sizeof(data));
659        mAppName = mAppList.back();
660        mAppList.pop_back();
661
662        buf.writeU8(NANOHUB_HAL_APP_MGMT);
663        writeAppName(buf, mAppName);
664        buf.writeU8(NANOHUB_HAL_APP_MGMT_START);
665        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
666    }
667}
668
669int SystemComm::AppMgmtSession::handleFinish(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager)
670{
671    if (rsp.mCmd != NANOHUB_HAL_FINISH_UPLOAD)
672        return 1;
673
674    mFlashAddr = buf.readU32();
675    uint32_t crc = buf.readU32();
676    mData.clear();
677
678    if (rsp.mStatus == 0) {
679        appManager.setCachedCrc(mAppName, crc);
680        char data[MAX_RX_PACKET];
681        MessageBuf buf(data, sizeof(data));
682        setState(RUN);
683
684        buf.writeU8(NANOHUB_HAL_APP_MGMT);
685        writeAppName(buf, mAppName);
686        buf.writeU8(NANOHUB_HAL_APP_MGMT_START);
687        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
688    } else {
689        int32_t result = NANOHUB_APP_NOT_LOADED;
690        appManager.clearCachedApp(mAppName);
691
692        sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
693        complete();
694        return 0;
695    }
696}
697
698int SystemComm::AppMgmtSession::handleRun(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager)
699{
700    if (rsp.mCmd != NANOHUB_HAL_APP_MGMT)
701        return 1;
702
703    uint8_t cmd = buf.readU8();
704
705    if (cmd != NANOHUB_HAL_APP_MGMT_START)
706        return 1;
707
708    MgmtStatus sts = { .value = buf.readU32() };
709
710    ALOGI("Nanohub NEW APP START: %08" PRIX32 "\n", sts.value);
711    if (rsp.mStatus == 0) {
712        appManager.setCachedStart(mAppName, true);
713        char data[MAX_RX_PACKET];
714        MessageBuf buf(data, sizeof(data));
715        setState(INFO);
716
717        buf.writeU8(NANOHUB_HAL_APP_INFO);
718        buf.writeU32(mFlashAddr);
719        buf.writeRaw(app_info_tags, sizeof(app_info_tags));
720
721        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
722    } else {
723        appManager.setCachedStart(mAppName, false);
724        int32_t result = NANOHUB_APP_NOT_LOADED;
725        sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
726        complete();
727        return 0;
728    }
729}
730
731int SystemComm::AppMgmtSession::handleInfo(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager)
732{
733    if (rsp.mCmd != NANOHUB_HAL_APP_INFO)
734        return 1;
735    int32_t result = 0;
736    size_t len = buf.getRoom();
737    if (len) {
738        appManager.readNanohubAppInfo(buf);
739        appManager.saveApps();
740    }
741    sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
742    complete();
743    return 0;
744}
745
746int SystemComm::AppMgmtSession::handleStopRun(NanohubRsp &rsp, MessageBuf &buf, AppManager &)
747{
748    if (rsp.mCmd != NANOHUB_HAL_APP_MGMT)
749        return 1;
750
751    uint8_t cmd = buf.readU8();
752
753    if (cmd != NANOHUB_HAL_APP_MGMT_STOP)
754        return 1;
755
756    MgmtStatus sts = { .value = buf.readU32() };
757
758    ALOGI("Nanohub NEW APP STOP: %08" PRIX32 "\n", sts.value);
759    if (rsp.mStatus == 0) {
760        char data[MAX_RX_PACKET];
761        MessageBuf buf(data, sizeof(data));
762        setState(RUN);
763
764        buf.writeU8(NANOHUB_HAL_APP_MGMT);
765        writeAppName(buf, mAppName);
766        buf.writeU8(NANOHUB_HAL_APP_MGMT_START);
767        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
768    } else {
769        int32_t result = NANOHUB_APP_NOT_LOADED;
770
771        sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
772        complete();
773        return 0;
774    }
775}
776
777/* reboot notification, when triggered by App request */
778int SystemComm::AppMgmtSession::handleReboot(NanohubRsp &rsp, MessageBuf &buf, AppManager &)
779{
780    if (rsp.mCmd != NANOHUB_HAL_SYS_MGMT)
781        return 1;
782
783    uint8_t cmd = buf.readU8();
784
785    if (cmd == NANOHUB_HAL_SYS_MGMT_REBOOT)
786        ALOGI("Nanohub reboot status [USER REQ]: %08" PRIX32 "\n", rsp.mStatus);
787
788    // reboot notification is sent by SessionManager
789    complete();
790
791    return 0;
792}
793
794int SystemComm::AppMgmtSession::handleEraseTransfer(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager)
795{
796    if (rsp.mCmd != NANOHUB_HAL_SYS_MGMT)
797        return 1;
798
799    uint8_t cmd = buf.readU8();
800
801    if (cmd == NANOHUB_HAL_SYS_MGMT_ERASE && rsp.mStatus == 0) {
802        char data[MAX_RX_PACKET];
803        MessageBuf buf(data, sizeof(data));
804        appManager.eraseApps();
805        setState(TRANSFER);
806
807        buf.writeU8(NANOHUB_HAL_START_UPLOAD);
808        buf.writeU8(0);
809        buf.writeU32(mLen);
810        return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
811    } else {
812        int32_t result = NANOHUB_APP_NOT_LOADED;
813
814        sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
815        complete();
816        return 0;
817    }
818}
819
820int SystemComm::AppMgmtSession::handleMgmt(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager)
821{
822    if (rsp.mCmd != NANOHUB_HAL_APP_MGMT)
823        return 1;
824
825    uint8_t cmd = buf.readU8();
826    MgmtStatus sts = { .value = buf.readU32() };
827
828    bool valid = false;
829
830    int32_t result = rsp.mStatus;
831
832    if (result != 0)
833        result = -1;
834
835    switch (cmd) {
836    case NANOHUB_HAL_APP_MGMT_STOP:
837        valid = mCmd == CONTEXT_HUB_APPS_DISABLE;
838        if (valid && rsp.mStatus == 0)
839            appManager.clearRunning(mAppName);
840        break;
841    case NANOHUB_HAL_APP_MGMT_START:
842        valid = mCmd == CONTEXT_HUB_APPS_ENABLE;
843        if (valid && rsp.mStatus == 0) {
844            appManager.setCachedStart(mAppName, true);
845            char data[MAX_RX_PACKET];
846            MessageBuf buf(data, sizeof(data));
847            setState(INFO);
848
849            buf.writeU8(NANOHUB_HAL_APP_INFO);
850            buf.writeU32(appManager.getFlashAddr(mAppName));
851            buf.writeRaw(app_info_tags, sizeof(app_info_tags));
852
853            return sendToSystem(buf.getData(), buf.getPos(), rsp.mTransactionId);
854        }
855        break;
856    case NANOHUB_HAL_APP_MGMT_UNLOAD:
857        valid = mCmd == CONTEXT_HUB_UNLOAD_APP;
858        if (valid && rsp.mStatus == 0)
859            appManager.clearRunning(mAppName);
860        break;
861    default:
862        return 1;
863    }
864
865    ALOGI("Nanohub MGMT response: CMD=%02X; STATUS=%08" PRIX32, rsp.mCmd, sts.value);
866    if (!valid) {
867        ALOGE("Invalid response for this state: APP CMD=%02X", mCmd);
868        return -EINVAL;
869    }
870
871    sendToApp(mCmd, rsp.mTransactionId, &result, sizeof(result));
872    complete();
873    return 0;
874}
875
876int SystemComm::KeyInfoSession::setup(const hub_message_t *, uint32_t transactionId, AppManager &) {
877    std::lock_guard<std::mutex> _l(mLock);
878    mKeyNum = 0;
879    mKeyOffset = 0;
880    mRsaKeyData.clear();
881    setState(SESSION_USER);
882    mStatus = -EBUSY;
883    return requestRsaKeys(transactionId);
884}
885
886int SystemComm::KeyInfoSession::handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &, bool chre)
887{
888    std::lock_guard<std::mutex> _l(mLock);
889    NanohubRsp rsp(buf, transactionId, chre);
890
891    if (getState() != SESSION_USER) {
892        // invalid state
893        mStatus = -EFAULT;
894        return mStatus;
895    }
896
897    uint32_t keyLen = buf.readU32();
898    uint32_t dataLen = buf.getRoom();
899
900    if (dataLen) {
901        mRsaKeyData.insert(mRsaKeyData.end(),
902                           buf.getData() + buf.getPos(),
903                           buf.getData() + buf.getSize());
904        if (mKeyOffset + dataLen >= keyLen) {
905            mKeyNum++;
906            mKeyOffset = 0;
907        } else {
908            mKeyOffset += dataLen;
909        }
910        return requestRsaKeys(transactionId);
911    } else {
912        mStatus = 0;
913        complete();
914        return 0;
915    }
916}
917
918int SystemComm::KeyInfoSession::requestRsaKeys(uint32_t transactionId)
919{
920    char data[MAX_RX_PACKET];
921    MessageBuf buf(data, sizeof(data));
922
923    buf.writeU8(NANOHUB_HAL_KEY_INFO);
924    buf.writeU32(mKeyNum);
925    buf.writeU32(mKeyOffset);
926
927    return sendToSystem(buf.getData(), buf.getPos(), transactionId);
928}
929
930void SystemComm::AppManager::dumpAppInfo(std::string &result)
931{
932    char buffer[256];
933
934    for (auto &it : apps_) {
935        uint64_t id = it.first;
936        const auto &app = it.second;
937
938        snprintf(buffer, sizeof(buffer), "App: 0x%016" PRIx64 "\n", id);
939        result.append(buffer);
940        if (app->loaded) {
941            snprintf(buffer, sizeof(buffer),
942                "  Version: 0x%08" PRIx32 "\n"
943                "  flashAddr: 0x%08" PRIx32 "\n"
944                "  Running: %s\n",
945                app->version,
946                app->flashAddr,
947                app->running ? "true" : "false");
948            result.append(buffer);
949
950            if (app->flashUse != NANOHUB_MEM_SZ_UNKNOWN) {
951                snprintf(buffer, sizeof(buffer),
952                    "  flashUse: %d\n"
953                    "  CRC: 0x%08" PRIx32 "\n",
954                    app->flashUse,
955                    app->crc);
956                result.append(buffer);
957            }
958
959            if (app->running) {
960                snprintf(buffer, sizeof(buffer),
961                    "  TID: %04x\n"
962                    "  ramUse: %d\n",
963                    app->tid,
964                    app->ramUse);
965                result.append(buffer);
966            }
967
968            if (app->chre) {
969                snprintf(buffer, sizeof(buffer), "  CHRE: %d.%d\n",
970                    app->chre_major, app->chre_minor);
971                result.append(buffer);
972            }
973        }
974
975        if (app->cached_napp) {
976            snprintf(buffer, sizeof(buffer),
977                "  Cached Version: 0x%08" PRIx32 "\n"
978                "  Cached Start: %s\n"
979                "  Cached CRC: 0x%08" PRIx32 "\n",
980                app->cached_version,
981                app->cached_start ? "true" : "false",
982                app->cached_crc);
983            result.append(buffer);
984        }
985    }
986}
987
988bool SystemComm::AppManager::saveApps()
989{
990    mkdir(CHRE_APP_DIR, CHRE_APP_DIR_PERMS);
991    File saved_apps_file(CHRE_APP_SETTINGS, "w");
992    std::shared_ptr<Json::Value> appsObject(new Json::Value);
993    status_t err;
994
995    if ((err = saved_apps_file.initCheck()) != OK) {
996        ALOGW("saved_apps file open (w) failed %d (%s)",
997              err,
998              strerror(-err));
999        return false;
1000    }
1001
1002    for (auto &it : apps_) {
1003        uint64_t id = it.first;
1004        const auto &app = it.second;
1005
1006        if (app->cached_napp) {
1007            char hexId[17];
1008            snprintf(hexId, sizeof(hexId), "%016" PRIX64, id);
1009            Json::Value array(Json::arrayValue);
1010            array[0] = app->cached_version;
1011            array[1] = app->cached_start;
1012            array[2] = app->cached_crc;
1013            (*appsObject)[hexId] = array;
1014        }
1015    }
1016
1017    // Write the JSON string to disk.
1018    Json::StyledWriter writer;
1019    std::string serializedSettings(writer.write(*appsObject));
1020    size_t size = serializedSettings.size();
1021    if ((err = saved_apps_file.write(serializedSettings.c_str(), size)) != (ssize_t)size) {
1022        ALOGW("saved_apps file write failed %d (%s)",
1023              err,
1024              strerror(-err));
1025        return false;
1026    }
1027
1028    return true;
1029}
1030
1031bool SystemComm::AppManager::restoreApps()
1032{
1033    File saved_apps_file(CHRE_APP_SETTINGS, "r");
1034    std::shared_ptr<Json::Value> appsObject;
1035    status_t err;
1036
1037    if ((err = saved_apps_file.initCheck()) != OK) {
1038        ALOGW("saved_apps file open (r) failed %d (%s)",
1039              err,
1040              strerror(-err));
1041        return false;
1042    }
1043
1044    off64_t size = saved_apps_file.seekTo(0, SEEK_END);
1045    saved_apps_file.seekTo(0, SEEK_SET);
1046
1047    if (size > 0) {
1048        char *buf = (char *)malloc(size);
1049        CHECK_EQ(saved_apps_file.read(buf, size), (ssize_t)size);
1050
1051        std::string str(buf);
1052        std::shared_ptr<Json::Value> in(new Json::Value);
1053        Json::Reader reader;
1054        bool valid = reader.parse(str, *in);
1055        free(buf);
1056
1057        if (valid && in->isObject()) {
1058            appsObject = in;
1059        }
1060    }
1061
1062    if (appsObject == nullptr) {
1063        appsObject = std::shared_ptr<Json::Value>(new Json::Value(Json::objectValue));
1064    }
1065
1066    Json::Value::Members apps = appsObject->getMemberNames();
1067    for (auto &it : apps) {
1068        Json::Value &val = (*appsObject)[it];
1069        if (val.isArray()) {
1070            uint32_t version = val[0].asUInt();
1071            uint32_t start = val[1].asUInt();
1072            uint32_t crc = val[2].asUInt();
1073
1074            uint64_t id = strtoull(it.c_str(), nullptr, 16);
1075            apps_[id] = std::unique_ptr<AppData>(new AppData);
1076            apps_[id]->loaded = false;
1077            apps_[id]->running = false;
1078            apps_[id]->chre = false;
1079            apps_[id]->cached_napp = true;
1080            apps_[id]->cached_version = version;
1081            apps_[id]->cached_start = start;
1082            apps_[id]->cached_crc = crc;
1083        }
1084    }
1085
1086    return true;
1087}
1088
1089bool SystemComm::AppManager::eraseApps()
1090{
1091    for (auto it=apps_.begin(); it != apps_.end();) {
1092        if (!it->second->cached_napp)
1093            it = apps_.erase(it);
1094        else {
1095            it->second->loaded = false;
1096            it->second->running = false;
1097            it->second->chre = false;
1098            ++it;
1099        }
1100    }
1101
1102    return true;
1103}
1104
1105bool SystemComm::AppManager::writeApp(hub_app_name_t &appName, const uint8_t *data, int32_t len)
1106{
1107    mkdir(CHRE_APP_DIR, CHRE_APP_DIR_PERMS);
1108    char file[strlen(CHRE_APP_DIR) + strlen("/") + 16 + strlen(".napp") + 1];
1109
1110    snprintf(file, sizeof(file), "%s/%016" PRIX64 ".napp", CHRE_APP_DIR, appName.id);
1111
1112    int fd = open(file, O_CREAT | O_WRONLY | O_TRUNC, CHRE_APP_FILE_PERMS);
1113    if (fd == -1)
1114        return false;
1115
1116    if (write(fd, data, len) == len) {
1117        close(fd);
1118        return true;
1119    } else {
1120        close(fd);
1121        return false;
1122    }
1123}
1124
1125int32_t SystemComm::AppManager::readApp(hub_app_name_t &appName, void **data)
1126{
1127    char file[strlen(CHRE_APP_DIR) + strlen("/") + 16 + strlen(".napp") + 1];
1128
1129    snprintf(file, sizeof(file), "%s/%016" PRIX64 ".napp", CHRE_APP_DIR, appName.id);
1130
1131    int32_t ret = -1;
1132    *data = nullptr;
1133    int fd = open(file, O_RDONLY);
1134
1135    if (fd >= 0) {
1136        struct stat sb;
1137        if (fstat(fd, &sb) == 0) {
1138            *data = malloc(sb.st_size);
1139            if (*data != nullptr && read(fd, *data, sb.st_size) == sb.st_size)
1140                ret = sb.st_size;
1141            else {
1142                free(*data);
1143                *data = nullptr;
1144            }
1145        }
1146        close(fd);
1147    }
1148    return ret;
1149}
1150
1151bool SystemComm::AppManager::cmpApp(hub_app_name_t &appName, const uint8_t *data, uint32_t len)
1152{
1153    char file[strlen(CHRE_APP_DIR) + strlen("/") + 16 + strlen(".napp") + 1];
1154
1155    snprintf(file, sizeof(file), "%s/%016" PRIX64 ".napp", CHRE_APP_DIR, appName.id);
1156
1157    if (!isAppLoaded(appName))
1158        return false;
1159
1160    if ((!apps_[appName.id]->cached_napp) ||
1161        (apps_[appName.id]->crc != apps_[appName.id]->cached_crc))
1162        return false;
1163
1164    bool success = false;
1165    int fd = open(file, O_RDONLY);
1166
1167    if (fd >= 0) {
1168        struct stat sb;
1169        if (fstat(fd, &sb) == 0 && sb.st_size == len) {
1170            void *buf = malloc(len);
1171            if (buf != nullptr && read(fd, buf, sb.st_size) == sb.st_size && memcmp(data, buf, len) == 0)
1172                success = true;
1173            free(buf);
1174        }
1175        close(fd);
1176    }
1177    return success;
1178}
1179
1180uint32_t SystemComm::AppManager::readNanohubAppInfo(MessageBuf &buf)
1181{
1182    hub_app_name_t name;
1183
1184    uint8_t tag, len;
1185    uint32_t ramUse = 0;
1186    bool ramUseValid = true;
1187
1188    // first tag must be the appid
1189    if (buf.getRoom() < 2 + sizeof(name.id)) {
1190        ALOGE("%s: failed to read object", __func__);
1191        return 0;
1192    }
1193
1194    tag = buf.readU8();
1195    len = buf.readU8();
1196    if (tag != NANOHUB_HAL_APP_INFO_APPID || len != sizeof(name.id)) {
1197        ALOGE("%s: invalid first tag: %d", __func__, tag);
1198        return 0;
1199    }
1200
1201    readAppName(buf, name);
1202    if (!isAppPresent(name)) {
1203        apps_[name.id] = std::unique_ptr<AppData>(new AppData);
1204        apps_[name.id]->loaded = false;
1205        apps_[name.id]->chre = false;
1206        apps_[name.id]->running = false;
1207        apps_[name.id]->cached_napp = false;
1208    }
1209    const auto &app = apps_[name.id];
1210
1211    while (buf.getRoom() >= 2) {
1212        tag = buf.readU8();
1213        len = buf.readU8();
1214        if (buf.getRoom() >= len) {
1215            switch(tag) {
1216            case NANOHUB_HAL_APP_INFO_CRC:
1217                if (len == 0)
1218                    app->crc = 0;
1219                else if (len == sizeof(app->crc))
1220                    app->crc = buf.readU32();
1221                else
1222                    buf.readRaw(len);
1223                break;
1224            case NANOHUB_HAL_APP_INFO_TID:
1225                if (len == 0) {
1226                    app->tid = NANOHUB_TID_UNKNOWN;
1227                    ramUseValid = false;
1228                    app->loaded = true;
1229                    app->running = false;
1230                } else if (len  == sizeof(app->tid)) {
1231                    app->tid = buf.readU32();
1232                    app->loaded = true;
1233                    app->running = true;
1234                } else
1235                    buf.readRaw(len);
1236                break;
1237            case NANOHUB_HAL_APP_INFO_VERSION:
1238                if (len == sizeof(app->version))
1239                    app->version = buf.readU32();
1240                else
1241                    buf.readRaw(len);
1242                break;
1243            case NANOHUB_HAL_APP_INFO_ADDR:
1244                if (len == sizeof(app->flashAddr))
1245                    app->flashAddr = buf.readU32();
1246                else
1247                    buf.readRaw(len);
1248                break;
1249            case NANOHUB_HAL_APP_INFO_SIZE:
1250                if (len == 0)
1251                    app->flashUse = NANOHUB_MEM_SZ_UNKNOWN;
1252                else if (len == sizeof(app->flashUse))
1253                    app->flashUse = buf.readU32();
1254                else
1255                    buf.readRaw(len);
1256                break;
1257            case NANOHUB_HAL_APP_INFO_HEAP:
1258            case NANOHUB_HAL_APP_INFO_DATA:
1259            case NANOHUB_HAL_APP_INFO_BSS:
1260                if (len == 0)
1261                    ramUseValid = false;
1262                else if (len == sizeof(uint32_t))
1263                    ramUse += buf.readU32();
1264                else
1265                    buf.readRaw(len);
1266                break;
1267            case NANOHUB_HAL_APP_INFO_CHRE_MAJOR:
1268                if (len == 0)
1269                    app->chre = false;
1270                else if (len == sizeof(app->chre_major)) {
1271                    app->chre = true;
1272                    app->chre_major = buf.readU8();
1273                } else
1274                    buf.readRaw(len);
1275                break;
1276            case NANOHUB_HAL_APP_INFO_CHRE_MINOR:
1277                if (len == 0)
1278                    app->chre = false;
1279                else if (len == sizeof(app->chre_minor)) {
1280                    app->chre = true;
1281                    app->chre_minor = buf.readU8();
1282                } else
1283                    buf.readRaw(len);
1284                break;
1285            case NANOHUB_HAL_APP_INFO_END:
1286                if (len != 0 || buf.getRoom() != 0) {
1287                    ALOGE("%s: failed to read object", __func__);
1288                    return 0;
1289                }
1290                break;
1291            default:
1292                ALOGI("%s: unsupported tag: %d", __func__, tag);
1293                buf.readRaw(len);
1294                break;
1295            }
1296        } else {
1297            ALOGE("%s: failed to read object", __func__);
1298            return 0;
1299        }
1300    }
1301
1302    if (buf.getRoom() != 0) {
1303        ALOGE("%s: failed to read object", __func__);
1304        return 0;
1305    }
1306
1307    if (ramUseValid)
1308        app->ramUse = ramUse;
1309    else
1310        app->ramUse = NANOHUB_MEM_SZ_UNKNOWN;
1311
1312    return app->flashAddr +
1313        (app->flashUse != NANOHUB_MEM_SZ_UNKNOWN ? ((app->flashUse+3)&~3) : 4);
1314}
1315
1316void SystemComm::AppManager::sendAppInfoToApp(uint32_t transactionId) {
1317    std::vector<hub_app_info> appInfo;
1318    for (auto &it : apps_) {
1319        uint64_t id = it.first;
1320        const auto &app = it.second;
1321
1322        // TODO: Still have some non-chre apps that need to be reported
1323        // if (!app->chre || !app->running || app->flashUse == NANOHUB_MEM_SZ_UNKNOWN)
1324        if (!app->running || app->flashUse == NANOHUB_MEM_SZ_UNKNOWN)
1325            continue;
1326
1327        hub_app_info info;
1328        info.app_name = { .id = id };
1329        info.version = app->version;
1330        info.num_mem_ranges = 0;
1331        if (app->flashUse != NANOHUB_MEM_SZ_UNKNOWN) {
1332            mem_range_t &range = info.mem_usage[info.num_mem_ranges++];
1333            range.type = HUB_MEM_TYPE_MAIN;
1334            range.total_bytes = app->flashUse;
1335        }
1336        if (app->ramUse != NANOHUB_MEM_SZ_UNKNOWN) {
1337            mem_range_t &range = info.mem_usage[info.num_mem_ranges++];
1338            range.type = HUB_MEM_TYPE_RAM;
1339            range.total_bytes = app->ramUse;
1340        }
1341
1342        appInfo.push_back(info);
1343    }
1344    sendToApp(CONTEXT_HUB_QUERY_APPS, transactionId,
1345              static_cast<const void *>(appInfo.data()),
1346              appInfo.size() * sizeof(appInfo[0]));
1347}
1348
1349int SystemComm::AppManager::getAppsToStart(std::vector<hub_app_name_t> &apps)
1350{
1351    int cnt = 0;
1352    apps.clear();
1353
1354    for (auto &it : apps_) {
1355        uint64_t id = it.first;
1356        const auto &app = it.second;
1357
1358        if (app->cached_napp && app->cached_start && app->loaded &&
1359            !app->running && app->flashUse != NANOHUB_MEM_SZ_UNKNOWN) {
1360            apps.push_back({ .id = id });
1361            cnt++;
1362        }
1363    }
1364
1365    return cnt;
1366}
1367
1368int SystemComm::doHandleRx(uint64_t appId, uint32_t transactionId, const char *data, int len, bool chre)
1369{
1370    bool reboot = false;
1371    uint32_t rebootStatus;
1372    //we only care for messages from HostIF
1373    if (appId != mHostIfAppName.id)
1374        return 1;
1375
1376    //they must all be at least 1 byte long
1377    if (!len) {
1378        return -EINVAL;
1379    }
1380    MessageBuf buf(data, len);
1381    if (NanoHub::messageTracingEnabled()) {
1382        dumpBuffer("SYS -> HAL", mHostIfAppName, transactionId, 0, buf.getData(), buf.getSize());
1383    }
1384    int status = mSessions.handleRx(buf, transactionId, mAppManager, chre, reboot, rebootStatus);
1385    if (status) {
1386        // provide default handler for any system message, that is not properly handled
1387        dumpBuffer(status > 0 ? "HAL (not handled)" : "HAL (error)",
1388                   mHostIfAppName, transactionId, 0, buf.getData(), buf.getSize(), status);
1389        status = status > 0 ? 0 : status;
1390    }
1391    if (reboot) {
1392        hub_message_t msg =
1393        {
1394            .app_name.id = appId,
1395            .message_type = CONTEXT_HUB_START_APPS,
1396            .message_len = sizeof(rebootStatus),
1397            .message = &rebootStatus,
1398        };
1399
1400        status = doHandleTx(&msg, 0xFFFFFFFF);
1401    }
1402
1403    return status;
1404}
1405
1406void SystemComm::doDumpAppInfo(std::string &result)
1407{
1408    mAppManager.dumpAppInfo(result);
1409}
1410
1411int SystemComm::SessionManager::handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre, bool &reboot, uint32_t &rebootStatus)
1412{
1413    int status = 1;
1414    std::unique_lock<std::mutex> lk(lock);
1415
1416    // pass message to all active sessions, in arbitrary order
1417    // 1st session that handles the message terminates the loop
1418    for (auto pos = sessions_.begin(); pos != sessions_.end() && status > 0; next(pos)) {
1419        if (!isActive(pos)) {
1420            continue;
1421        }
1422        Session *session = pos->second;
1423        status = session->handleRx(buf, transactionId, appManager, chre);
1424        if (status < 0) {
1425            session->complete();
1426        }
1427    }
1428
1429    NanohubRsp rsp(buf, transactionId, chre);
1430    if (rsp.mCmd == NANOHUB_HAL_SYS_MGMT) {
1431        uint8_t cmd = buf.readU8();
1432
1433        if (cmd == NANOHUB_HAL_SYS_MGMT_REBOOT) {
1434            // if this is reboot notification, kill all sessions
1435            for (auto pos = sessions_.begin(); pos != sessions_.end(); next(pos)) {
1436                if (!isActive(pos)) {
1437                    continue;
1438                }
1439                Session *session = pos->second;
1440                session->abort(-EINTR);
1441            }
1442            lk.unlock();
1443            // log the reboot event, if not handled
1444            if (status > 0) {
1445                ALOGW("Nanohub reboot status [UNSOLICITED]: %08" PRIX32, rsp.mStatus);
1446                status = 0;
1447            }
1448            reboot = true;
1449            rebootStatus = rsp.mStatus;
1450        }
1451    }
1452
1453    return status;
1454}
1455
1456int SystemComm::SessionManager::setup_and_add(int id, Session *session, const hub_message_t *appMsg, uint32_t transactionId, AppManager &appManager)
1457{
1458    std::lock_guard<std::mutex> _l(lock);
1459
1460    // scan sessions to release those that are already done
1461    for (auto pos = sessions_.begin(); pos != sessions_.end(); next(pos)) {
1462        continue;
1463    }
1464
1465    if (sessions_.count(id) == 0 && !session->isRunning()) {
1466        sessions_[id] = session;
1467        int ret = session->setup(appMsg, transactionId, appManager);
1468        if (ret < 0) {
1469            session->complete();
1470        }
1471        return ret;
1472    }
1473    return -EBUSY;
1474}
1475
1476int SystemComm::doHandleTx(const hub_message_t *appMsg, uint32_t transactionId)
1477{
1478    int status = 0;
1479
1480    switch (appMsg->message_type) {
1481    case CONTEXT_HUB_LOAD_APP:
1482        if (!mKeySession.haveKeys()) {
1483            status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mKeySession, appMsg, transactionId, mAppManager);
1484            if (status < 0) {
1485                break;
1486            }
1487            mKeySession.wait();
1488            status = mKeySession.getStatus();
1489            if (status < 0) {
1490                break;
1491            }
1492        }
1493        status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg, transactionId, mAppManager);
1494        break;
1495    case CONTEXT_HUB_APPS_ENABLE:
1496    case CONTEXT_HUB_APPS_DISABLE:
1497    case CONTEXT_HUB_UNLOAD_APP:
1498        // all APP-modifying commands share session key, to ensure they can't happen at the same time
1499        status = mSessions.setup_and_add(CONTEXT_HUB_LOAD_APP, &mAppMgmtSession, appMsg, transactionId, mAppManager);
1500        break;
1501
1502    case CONTEXT_HUB_QUERY_APPS:
1503        mAppManager.sendAppInfoToApp(transactionId);
1504        break;
1505
1506    case CONTEXT_HUB_QUERY_MEMORY:
1507        status = mSessions.setup_and_add(CONTEXT_HUB_QUERY_MEMORY, &mMemInfoSession, appMsg, transactionId, mAppManager);
1508        break;
1509
1510    case CONTEXT_HUB_START_APPS:
1511        status = mSessions.setup_and_add(CONTEXT_HUB_START_APPS, &mAppMgmtSession, appMsg, transactionId, mAppManager);
1512        break;
1513
1514    default:
1515        ALOGW("Unknown os message type %u\n", appMsg->message_type);
1516        return -EINVAL;
1517    }
1518
1519   return status;
1520}
1521
1522}; // namespace nanohub
1523
1524}; // namespace android
1525