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 #ifndef _NANOHUB_SYSTEM_COMMS_H_
18 #define _NANOHUB_SYSTEM_COMMS_H_
19 
20 #include <utils/Condition.h>
21 
22 #include <chrono>
23 #include <condition_variable>
24 #include <map>
25 #include <mutex>
26 #include <vector>
27 
28 #include <hardware/context_hub.h>
29 #include <nanohub/nanohub.h>
30 
31 #include "nanohubhal.h"
32 #include "message_buf.h"
33 
34 //rx: return 0 if handled, > 0 if not handled, < 0 if error happened
35 
36 #define MSG_HANDLED 0
37 
38 //messages to the HostIf nanoapp & their replies (mesages and replies both begin with u8 message_type)
39 #define NANOHUB_HAL_APP_MGMT      0x10 // (char cmd, u64 appId, u64 appMsk) -> (int errno, u32 results)
40 
41 #define NANOHUB_HAL_APP_MGMT_START      0
42 #define NANOHUB_HAL_APP_MGMT_STOP       1
43 #define NANOHUB_HAL_APP_MGMT_UNLOAD     2
44 #define NANOHUB_HAL_APP_MGMT_DELETE     3
45 
46 #define NANOHUB_HAL_SYS_MGMT      0x11 // (char cmd) -> (int errno)
47 
48 #define NANOHUB_HAL_SYS_MGMT_ERASE      0
49 #define NANOHUB_HAL_SYS_MGMT_REBOOT     1
50 
51 #define NANOHUB_HAL_APP_INFO      0x12
52 
53 #define NANOHUB_HAL_APP_INFO_APPID          0x00
54 #define NANOHUB_HAL_APP_INFO_CRC            0x01
55 #define NANOHUB_HAL_APP_INFO_TID            0x02
56 #define NANOHUB_HAL_APP_INFO_VERSION        0x03
57 #define NANOHUB_HAL_APP_INFO_ADDR           0x04
58 #define NANOHUB_HAL_APP_INFO_SIZE           0x05
59 #define NANOHUB_HAL_APP_INFO_HEAP           0x06
60 #define NANOHUB_HAL_APP_INFO_DATA           0x07
61 #define NANOHUB_HAL_APP_INFO_BSS            0x08
62 #define NANOHUB_HAL_APP_INFO_CHRE_MAJOR     0x09
63 #define NANOHUB_HAL_APP_INFO_CHRE_MINOR     0x0A
64 #define NANOHUB_HAL_APP_INFO_END            0xFF
65 
66 #define NANOHUB_HAL_SYS_INFO      0x13
67 
68 #define NANOHUB_HAL_SYS_INFO_HEAP_FREE      0x0F
69 #define NANOHUB_HAL_SYS_INFO_RAM_SIZE       0x12
70 #define NANOHUB_HAL_SYS_INFO_EEDATA_SIZE    0x13
71 #define NANOHUB_HAL_SYS_INFO_EEDATA_FREE    0x14
72 #define NANOHUB_HAL_SYS_INFO_CODE_SIZE      0x15
73 #define NANOHUB_HAL_SYS_INFO_CODE_FREE      0x16
74 #define NANOHUB_HAL_SYS_INFO_SHARED_SIZE    0x17
75 #define NANOHUB_HAL_SYS_INFO_SHARED_FREE    0x18
76 #define NANOHUB_HAL_SYS_INFO_END            0xFF
77 
78 #define NANOHUB_HAL_KEY_INFO      0x14
79 #define NANOHUB_HAL_START_UPLOAD  0x16
80 #define NANOHUB_HAL_CONT_UPLOAD   0x17
81 #define NANOHUB_HAL_FINISH_UPLOAD 0x18
82 
83 #define NANOHUB_HAL_UPLOAD_ACCEPTED         0
84 #define NANOHUB_HAL_UPLOAD_WAIT             1
85 #define NANOHUB_HAL_UPLOAD_RESEND           2
86 #define NANOHUB_HAL_UPLOAD_RESTART          3
87 #define NANOHUB_HAL_UPLOAD_CANCEL           4
88 #define NANOHUB_HAL_UPLOAD_CANCEL_NO_RETRY  5
89 #define NANOHUB_HAL_UPLOAD_NO_SPACE         6
90 
91 #define NANOHUB_APP_NOT_LOADED  (-1)
92 #define NANOHUB_APP_LOADED      (0)
93 
94 #define NANOHUB_UPLOAD_CHUNK_SZ_MAX 64
95 #define NANOHUB_MEM_SZ_UNKNOWN      0xFFFFFFFFUL
96 #define NANOHUB_TID_UNKNOWN         0xFFFFFFFFUL
97 
98 #define CONTEXT_HUB_START_APPS      8
99 
100 namespace android {
101 
102 namespace nanohub {
103 
104 int system_comms_handle_rx(const nano_message_raw *msg);
105 int system_comms_handle_tx(const hub_message_t *outMsg);
106 
107 struct MgmtStatus {
108     union {
109         uint32_t value;
110         struct {
111             uint8_t app;
112             uint8_t task;
113             uint8_t op;
114             uint8_t erase;
115         } __attribute__((packed));
116     };
117 } __attribute__((packed));
118 
119 struct NanohubMemInfo {
120     //sizes
121     uint32_t flashSz, blSz, osSz, sharedSz, eeSz;
122     uint32_t ramSz;
123 
124     //use
125     uint32_t blUse, osUse, sharedUse, eeUse;
126     uint32_t ramUse;
127 } __attribute__((packed));
128 
129 struct NanohubRsp {
130     uint32_t mCmd;
131     uint32_t mTransactionId;
132     int32_t mStatus;
133     explicit NanohubRsp(MessageBuf &buf, uint32_t transactionId, bool chre);
134 };
135 
136 inline bool operator == (const hub_app_name_t &a, const hub_app_name_t &b) {
137     return a.id == b.id;
138 }
139 
140 inline bool operator != (const hub_app_name_t &a, const hub_app_name_t &b) {
141     return !(a == b);
142 }
143 
144 class SystemComm {
145 private:
146 
147     class AppManager;
148 
149     /*
150      * Nanohub HAL sessions
151      *
152      * Session is an object that can group several message exchanges with FW,
153      * maintain state, and be waited for completion by someone else.
154      *
155      * As of this moment, since all sessions are triggered by client thread,
156      * and all the exchange is happening in local worker thread, it is only possible
157      * for client thread to wait on session completion.
158      * Allowing sessions to wait on each other will require a worker thread pool.
159      * It is now unnecessary, and not implemented.
160      */
161     class ISession {
162     public:
163         virtual int setup(const hub_message_t *app_msg, uint32_t transactionId, AppManager &appManager) = 0;
164         virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre) = 0;
165         virtual int getState() const = 0; // FSM state
166         virtual int getStatus() const = 0; // execution status (result code)
167         virtual void abort(int32_t) = 0;
~ISession()168         virtual ~ISession() {}
169     };
170 
171     class SessionManager;
172 
173     class Session : public ISession {
174         friend class SessionManager;
175 
176         mutable std::mutex mDoneMutex; // controls condition and state transitions
177         std::condition_variable mDoneCond;
178         volatile int mState;
179 
180     protected:
181         mutable std::mutex mLock; // serializes message handling
182         int32_t mStatus;
183 
184         enum {
185             SESSION_INIT = 0,
186             SESSION_DONE = 1,
187             SESSION_USER = 2,
188         };
189 
complete()190         void complete() {
191             std::unique_lock<std::mutex> lk(mDoneMutex);
192             if (mState != SESSION_DONE) {
193                 mState = SESSION_DONE;
194                 lk.unlock();
195                 mDoneCond.notify_all();
196             }
197         }
abort(int32_t status)198         void abort(int32_t status) {
199             std::lock_guard<std::mutex> _l(mLock);
200             mStatus = status;
201             complete();
202         }
setState(int state)203         void setState(int state) {
204             if (state == SESSION_DONE) {
205                 complete();
206             } else {
207                 std::lock_guard<std::mutex> _l(mDoneMutex);
208                 mState = state;
209             }
210         }
211     public:
Session()212         Session() { mState = SESSION_INIT; mStatus = -1; }
getStatus()213         int getStatus() const {
214             std::lock_guard<std::mutex> _l(mLock);
215             return mStatus;
216         }
wait()217         int wait() {
218             std::unique_lock<std::mutex> lk(mDoneMutex);
219             bool success = mDoneCond.wait_for(
220                     lk, std::chrono::seconds(30),
221                     [this] { return mState == SESSION_DONE; });
222             if (!success) {
223                 ALOGE("Timed out waiting for response");
224             }
225             return success ? 0 : -1;
226         }
getState()227         virtual int getState() const override {
228             std::lock_guard<std::mutex> _l(mDoneMutex);
229             return mState;
230         }
isDone()231         virtual bool isDone() const {
232             std::lock_guard<std::mutex> _l(mDoneMutex);
233             return mState == SESSION_DONE;
234         }
isRunning()235         virtual bool isRunning() const {
236             std::lock_guard<std::mutex> _l(mDoneMutex);
237             return mState > SESSION_DONE;
238         }
239     };
240 
241     class AppMgmtSession : public Session {
242         enum {
243             TRANSFER = SESSION_USER,
244             QUERY_START,
245             START,
246             STOP_TRANSFER,
247             FINISH,
248             RUN,
249             STOP_RUN,
250             RUN_FAILED,
251             REBOOT,
252             ERASE_TRANSFER,
253             MGMT,
254             INFO,
255         };
256         uint32_t mCmd; // LOAD_APP, UNLOAD_APP, ENABLE_APP, DISABLE_APP
257         uint32_t mResult;
258         std::vector<uint8_t> mData;
259         uint32_t mLen;
260         uint32_t mPos;
261         uint32_t mNextPos;
262         uint32_t mErrCnt;
263         hub_app_name_t mAppName;
264         uint32_t mFlashAddr;
265         std::vector<hub_app_name_t> mAppList;
266 
267         int setupMgmt(const hub_message_t *appMsg, uint32_t transactionId, uint32_t cmd, AppManager &appManager);
268         int handleTransfer(NanohubRsp &rsp, MessageBuf &, AppManager &appManager);
269         int handleStopTransfer(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
270         int handleQueryStart(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
271         int handleStart(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
272         int handleFinish(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
273         int handleRun(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
274         int handleStopRun(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
275         int handleReboot(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
276         int handleEraseTransfer(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
277         int handleMgmt(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
278         int handleInfo(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
279     public:
AppMgmtSession()280         AppMgmtSession() {
281             mCmd = 0;
282             mResult = 0;
283             mPos = 0;
284             mLen = 0;
285             memset(&mAppName, 0, sizeof(mAppName));
286         }
287         virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre) override;
288         virtual int setup(const hub_message_t *app_msg, uint32_t transactionId, AppManager &appManager) override;
289     };
290 
291     class MemInfoSession : public Session {
292     public:
293         virtual int setup(const hub_message_t *app_msg, uint32_t transactionId, AppManager &) override;
294         virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &, bool chre) override;
295     };
296 
297     class KeyInfoSession  : public Session {
298         std::vector<uint8_t> mRsaKeyData;
299         uint32_t mKeyNum;
300         uint32_t mKeyOffset;
301         int requestRsaKeys(uint32_t transactionId);
302     public:
303         virtual int setup(const hub_message_t *, uint32_t, AppManager &) override;
304         virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &, bool chre) override;
haveKeys()305         bool haveKeys() const {
306             std::lock_guard<std::mutex> _l(mLock);
307             return mRsaKeyData.size() > 0 && !isRunning();
308         }
309     };
310 
311     class AppManager {
312         struct AppData {
313             uint32_t version, flashUse, ramUse;
314             uint32_t tid, crc, flashAddr;
315             uint8_t chre_major, chre_minor;
316             bool chre, running, loaded;
317 
318             bool cached_start, cached_napp;
319             uint32_t cached_version, cached_crc;
320         };
321 
322         typedef std::map<uint64_t, std::unique_ptr<AppData>> AppMap;
323 
324         AppMap apps_;
325 
326     public:
AppManager()327         AppManager() {
328             restoreApps();
329         }
330         void dumpAppInfo(std::string &result);
331         bool saveApps();
332         bool restoreApps();
333         bool eraseApps();
334         bool writeApp(hub_app_name_t &appName, const uint8_t *data, int32_t len);
335         int32_t readApp(hub_app_name_t &appName, void **data);
336         bool cmpApp(hub_app_name_t &appName, const uint8_t *data, uint32_t len);
337         uint32_t readNanohubAppInfo(MessageBuf &buf);
338         void sendAppInfoToApp(uint32_t transactionId);
339         int getAppsToStart(std::vector<hub_app_name_t> &apps);
setCachedCrc(hub_app_name_t & appName,uint32_t crc)340         bool setCachedCrc(hub_app_name_t &appName, uint32_t crc) {
341             if (!isAppPresent(appName))
342                 return false;
343             else {
344                 apps_[appName.id]->cached_napp = true;
345                 apps_[appName.id]->cached_crc = crc;
346                 apps_[appName.id]->cached_start = false;
347                 saveApps();
348                 return true;
349             }
350         }
clearCachedApp(hub_app_name_t & appName)351         bool clearCachedApp(hub_app_name_t &appName) {
352             if (!isAppPresent(appName))
353                 return false;
354             else {
355                 apps_[appName.id]->cached_napp = false;
356                 apps_[appName.id]->cached_start = false;
357                 saveApps();
358                 return true;
359             }
360         }
clearRunning(hub_app_name_t & appName)361         bool clearRunning(hub_app_name_t &appName) {
362             if (!isAppLoaded(appName))
363                 return false;
364             else {
365                 apps_[appName.id]->running = false;
366                 return true;
367             }
368         }
369 
setCachedVersion(hub_app_name_t & appName,uint32_t version)370         bool setCachedVersion(hub_app_name_t &appName, uint32_t version) {
371             if (!isAppPresent(appName))
372                 return false;
373             else {
374                 apps_[appName.id]->cached_version = version;
375                 return true;
376             }
377         }
setCachedStart(hub_app_name_t & appName,bool start)378         bool setCachedStart(hub_app_name_t &appName, bool start) {
379             if (!isAppPresent(appName))
380                 return false;
381             else {
382                 apps_[appName.id]->cached_start = start;
383                 saveApps();
384                 return true;
385             }
386         }
addNewApp(hub_app_name_t & appName,uint32_t version)387         bool addNewApp(hub_app_name_t &appName, uint32_t version) {
388             if (isAppLoaded(appName))
389                 return false;
390             else
391                 apps_[appName.id] = std::unique_ptr<AppData>(new AppData);
392             apps_[appName.id]->loaded = false;
393             apps_[appName.id]->running = false;
394             apps_[appName.id]->chre = false;
395             apps_[appName.id]->cached_napp = false;
396             apps_[appName.id]->cached_version = version;
397             return true;
398         }
isAppPresent(hub_app_name_t & appName)399         bool isAppPresent(hub_app_name_t &appName) {
400             return apps_.count(appName.id) != 0;
401         }
isAppLoaded(hub_app_name_t & appName)402         bool isAppLoaded(hub_app_name_t &appName) {
403             return apps_.count(appName.id) != 0 && apps_[appName.id]->loaded;
404         }
isAppRunning(hub_app_name_t & appName)405         bool isAppRunning(hub_app_name_t &appName) {
406             return apps_.count(appName.id) != 0 && apps_[appName.id]->running;
407         }
getFlashAddr(hub_app_name_t & appName)408         uint32_t getFlashAddr(hub_app_name_t &appName) {
409             if (isAppPresent(appName))
410                 return apps_[appName.id]->flashAddr;
411             else
412                 return 0xFFFFFFFF;
413         }
414     };
415 
416     class SessionManager {
417         typedef std::map<int, Session* > SessionMap;
418 
419         std::mutex lock;
420         SessionMap sessions_;
421 
isActive(const SessionMap::iterator & pos)422         bool isActive(const SessionMap::iterator &pos) const
423         {
424             return !pos->second->isDone();
425         }
next(SessionMap::iterator & pos)426         void next(SessionMap::iterator &pos)
427         {
428             isActive(pos) ? pos++ : pos = sessions_.erase(pos);
429         }
430 
431     public:
432         int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre, bool &reboot, uint32_t &rebootStatus);
433         int setup_and_add(int id, Session *session, const hub_message_t *appMsg, uint32_t transactionId, AppManager &appManager);
434     } mSessions;
435 
436     const hub_app_name_t mHostIfAppName = {
437         .id = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0)
438     };
439 
getSystem()440     static SystemComm *getSystem() {
441         // this is thread-safe in c++11
442         static SystemComm theInstance;
443         return &theInstance;
444     }
445 
446     SystemComm () = default;
447     ~SystemComm() = default;
448 
449     int doHandleTx(const hub_message_t *txMsg, uint32_t transactionId);
450     int doHandleRx(uint64_t appId, uint32_t transactionId, const char *data, int len, bool chre);
451     void doDumpAppInfo(std::string &result);
452 
doHandleRx(const nano_message_raw * rxMsg)453     int doHandleRx(const nano_message_raw *rxMsg) {
454         return doHandleRx(rxMsg->hdr.appId, 0, reinterpret_cast<const char*>(rxMsg->data), rxMsg->hdr.len, false);
455     }
456 
doHandleRx(const nano_message_chre * rxMsg)457     int doHandleRx(const nano_message_chre *rxMsg) {
458         return doHandleRx(rxMsg->hdr.appId, rxMsg->hdr.appEventId, reinterpret_cast<const char*>(rxMsg->data), rxMsg->hdr.len, true);
459     }
460 
sendToApp(uint32_t typ,uint32_t transactionId,const void * data,uint32_t len)461     static void sendToApp(uint32_t typ, uint32_t transactionId, const void *data, uint32_t len) {
462         if (NanoHub::messageTracingEnabled()) {
463             dumpBuffer("HAL -> APP", get_hub_info()->os_app_name, transactionId, 0, data, len);
464         }
465         NanoHub::sendToApp(HubMessage(&get_hub_info()->os_app_name, typ, transactionId, ENDPOINT_BROADCAST, data, len));
466     }
467     static int sendToSystem(const void *data, size_t len, uint32_t transactionId);
468 
469     KeyInfoSession mKeySession;
470     AppMgmtSession mAppMgmtSession;
471     MemInfoSession mMemInfoSession;
472     AppManager     mAppManager;
473 
474 public:
handleTx(const hub_message_t * txMsg,uint32_t transactionId)475     static int handleTx(const hub_message_t *txMsg, uint32_t transactionId) {
476         return getSystem()->doHandleTx(txMsg, transactionId);
477     }
handleRx(const nano_message_raw * rxMsg)478     static int handleRx(const nano_message_raw *rxMsg) {
479         return getSystem()->doHandleRx(rxMsg);
480     }
handleRx(const nano_message_chre * rxMsg)481     static int handleRx(const nano_message_chre *rxMsg) {
482         return getSystem()->doHandleRx(rxMsg);
483     }
dumpAppInfo(std::string & result)484     static void dumpAppInfo(std::string &result) {
485         return getSystem()->doDumpAppInfo(result);
486     }
487 };
488 
489 }; // namespace nanohub
490 
491 }; // namespace android
492 
493 #endif
494