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 <condition_variable>
23 #include <map>
24 #include <mutex>
25 #include <vector>
26 
27 #include <hardware/context_hub.h>
28 #include <nanohub/nanohub.h>
29 
30 #include "nanohubhal.h"
31 #include "message_buf.h"
32 
33 //rx: return 0 if handled, > 0 if not handled, < 0 if error happened
34 
35 #define MSG_HANDLED 0
36 
37 //messages to the HostIf nanoapp & their replies (mesages and replies both begin with u8 message_type)
38 #define NANOHUB_EXT_APPS_ON        0 // () -> (char success)
39 #define NANOHUB_EXT_APPS_OFF       1 // () -> (char success)
40 #define NANOHUB_EXT_APP_DELETE     2 // (u64 name) -> (char success)    //idempotent
41 #define NANOHUB_QUERY_MEMINFO      3 // () -> (mem_info)
42 #define NANOHUB_QUERY_APPS         4 // (u32 idxStart) -> (app_info[idxStart] OR EMPTY IF NO MORE)
43 #define NANOHUB_QUERY_RSA_KEYS     5 // (u32 byteOffset) -> (u8 data[1 or more bytes] OR EMPTY IF NO MORE)
44 #define NANOHUB_START_UPLOAD       6 // (char isOs, u32 totalLenToTx) -> (char success)
45 #define NANOHUB_CONT_UPLOAD        7 // (u32 offset, u8 data[]) -> (char success)
46 #define NANOHUB_FINISH_UPLOAD      8 // () -> (char success)
47 #define NANOHUB_REBOOT             9 // () -> (char success)
48 
49 #define NANOHUB_APP_NOT_LOADED  (-1)
50 #define NANOHUB_APP_LOADED      (0)
51 
52 #define NANOHUB_UPLOAD_CHUNK_SZ_MAX 64
53 #define NANOHUB_MEM_SZ_UNKNOWN      0xFFFFFFFFUL
54 
55 namespace android {
56 
57 namespace nanohub {
58 
59 int system_comms_handle_rx(const nano_message *msg);
60 int system_comms_handle_tx(const hub_message_t *outMsg);
61 
62 struct NanohubAppInfo {
63     hub_app_name_t name;
64     uint32_t version, flashUse, ramUse;
65 } __attribute__((packed));
66 
67 struct MgmtStatus {
68     union {
69         uint32_t value;
70         struct {
71             uint8_t app;
72             uint8_t task;
73             uint8_t op;
74             uint8_t erase;
75         } __attribute__((packed));
76     };
77 } __attribute__((packed));
78 
79 struct NanohubMemInfo {
80     //sizes
81     uint32_t flashSz, blSz, osSz, sharedSz, eeSz;
82     uint32_t ramSz;
83 
84     //use
85     uint32_t blUse, osUse, sharedUse, eeUse;
86     uint32_t ramUse;
87 } __attribute__((packed));
88 
89 struct NanohubRsp {
90     uint32_t cmd;
91     int32_t status;
92     explicit NanohubRsp(MessageBuf &buf, bool no_status = false);
93 };
94 
95 inline bool operator == (const hub_app_name_t &a, const hub_app_name_t &b) {
96     return a.id == b.id;
97 }
98 
99 inline bool operator != (const hub_app_name_t &a, const hub_app_name_t &b) {
100     return !(a == b);
101 }
102 
103 class SystemComm {
104 private:
105 
106     /*
107      * Nanohub HAL sessions
108      *
109      * Session is an object that can group several message exchanges with FW,
110      * maintain state, and be waited for completion by someone else.
111      *
112      * As of this moment, since all sessions are triggered by client thread,
113      * and all the exchange is happening in local worker thread, it is only possible
114      * for client thread to wait on session completion.
115      * Allowing sessions to wait on each other will require a worker thread pool.
116      * It is now unnecessary, and not implemented.
117      */
118     class ISession {
119     public:
120         virtual int setup(const hub_message_t *app_msg) = 0;
121         virtual int handleRx(MessageBuf &buf) = 0;
122         virtual int getState() const = 0; // FSM state
123         virtual int getStatus() const = 0; // execution status (result code)
124         virtual void abort(int32_t) = 0;
~ISession()125         virtual ~ISession() {}
126     };
127 
128     class SessionManager;
129 
130     class Session : public ISession {
131         friend class SessionManager;
132 
133         mutable std::mutex mDoneMutex; // controls condition and state transitions
134         std::condition_variable mDoneCond;
135         volatile int mState;
136 
137     protected:
138         mutable std::mutex mLock; // serializes message handling
139         int32_t mStatus;
140 
141         enum {
142             SESSION_INIT = 0,
143             SESSION_DONE = 1,
144             SESSION_USER = 2,
145         };
146 
complete()147         void complete() {
148             std::unique_lock<std::mutex> lk(mDoneMutex);
149             if (mState != SESSION_DONE) {
150                 mState = SESSION_DONE;
151                 lk.unlock();
152                 mDoneCond.notify_all();
153             }
154         }
abort(int32_t status)155         void abort(int32_t status) {
156             std::lock_guard<std::mutex> _l(mLock);
157             mStatus = status;
158             complete();
159         }
setState(int state)160         void setState(int state) {
161             if (state == SESSION_DONE) {
162                 complete();
163             } else {
164                 std::lock_guard<std::mutex> _l(mDoneMutex);
165                 mState = state;
166             }
167         }
168     public:
Session()169         Session() { mState = SESSION_INIT; mStatus = -1; }
getStatus()170         int getStatus() const {
171             std::lock_guard<std::mutex> _l(mLock);
172             return mStatus;
173         }
wait()174         int wait() {
175             std::unique_lock<std::mutex> lk(mDoneMutex);
176             mDoneCond.wait(lk, [this] { return mState == SESSION_DONE; });
177             return 0;
178         }
getState()179         virtual int getState() const override {
180             std::lock_guard<std::mutex> _l(mDoneMutex);
181             return mState;
182         }
isDone()183         virtual bool isDone() const {
184             std::lock_guard<std::mutex> _l(mDoneMutex);
185             return mState == SESSION_DONE;
186         }
isRunning()187         virtual bool isRunning() const {
188             std::lock_guard<std::mutex> _l(mDoneMutex);
189             return mState > SESSION_DONE;
190         }
191     };
192 
193     class AppMgmtSession : public Session {
194         enum {
195             TRANSFER = SESSION_USER,
196             FINISH,
197             RUN,
198             RUN_FAILED,
199             REBOOT,
200             MGMT,
201         };
202         uint32_t mCmd; // LOAD_APP, UNLOAD_APP, ENABLE_APP, DISABLE_APP
203         uint32_t mResult;
204         std::vector<uint8_t> mData;
205         uint32_t mLen;
206         uint32_t mPos;
207         hub_app_name_t mAppName;
208 
209         int setupMgmt(const hub_message_t *appMsg, uint32_t cmd);
210         int handleTransfer(NanohubRsp &rsp);
211         int handleFinish(NanohubRsp &rsp);
212         int handleRun(NanohubRsp &rsp);
213         int handleRunFailed(NanohubRsp &rsp);
214         int handleReboot(NanohubRsp &rsp);
215         int handleMgmt(NanohubRsp &rsp);
216     public:
AppMgmtSession()217         AppMgmtSession() {
218             mCmd = 0;
219             mResult = 0;
220             mPos = 0;
221             mLen = 0;
222             memset(&mAppName, 0, sizeof(mAppName));
223         }
224         virtual int handleRx(MessageBuf &buf) override;
225         virtual int setup(const hub_message_t *app_msg) override;
226     };
227 
228     class MemInfoSession : public Session {
229     public:
230         virtual int setup(const hub_message_t *app_msg) override;
231         virtual int handleRx(MessageBuf &buf) override;
232     };
233 
234     class KeyInfoSession  : public Session {
235         std::vector<uint8_t> mRsaKeyData;
236         int requestRsaKeys(void);
237     public:
238         virtual int setup(const hub_message_t *) override;
239         virtual int handleRx(MessageBuf &buf) override;
haveKeys()240         bool haveKeys() const {
241             std::lock_guard<std::mutex> _l(mLock);
242             return mRsaKeyData.size() > 0 && !isRunning();
243         }
244     };
245 
246     class AppInfoSession : public Session {
247         std::vector<hub_app_info> mAppInfo;
248         int requestNext();
249     public:
250         virtual int setup(const hub_message_t *) override;
251         virtual int handleRx(MessageBuf &buf) override;
252     };
253 
254     class SessionManager {
255         typedef std::map<int, Session* > SessionMap;
256 
257         std::mutex lock;
258         SessionMap sessions_;
259 
isActive(const SessionMap::iterator & pos)260         bool isActive(const SessionMap::iterator &pos) const
261         {
262             return !pos->second->isDone();
263         }
next(SessionMap::iterator & pos)264         void next(SessionMap::iterator &pos)
265         {
266             isActive(pos) ? pos++ : pos = sessions_.erase(pos);
267         }
268 
269     public:
270         int handleRx(MessageBuf &buf);
271         int setup_and_add(int id, Session *session, const hub_message_t *appMsg);
272     } mSessions;
273 
274     const hub_app_name_t mHostIfAppName = {
275         .id = APP_ID_MAKE(NANOHUB_VENDOR_GOOGLE, 0)
276     };
277 
getSystem()278     static SystemComm *getSystem() {
279         // this is thread-safe in c++11
280         static SystemComm theInstance;
281         return &theInstance;
282     }
283 
284     SystemComm () = default;
285     ~SystemComm() = default;
286 
287     int doHandleTx(const hub_message_t *txMsg);
288     int doHandleRx(const nano_message *rxMsg);
289 
sendToApp(uint32_t typ,const void * data,uint32_t len)290     static void sendToApp(uint32_t typ, const void *data, uint32_t len) {
291         if (NanoHub::messageTracingEnabled()) {
292             dumpBuffer("HAL -> APP", get_hub_info()->os_app_name, typ, data, len);
293         }
294         NanoHub::sendToApp(HubMessage(&get_hub_info()->os_app_name, typ, data, len));
295     }
296     static int sendToSystem(const void *data, size_t len);
297 
298     KeyInfoSession mKeySession;
299     AppMgmtSession mAppMgmtSession;
300     AppInfoSession mAppInfoSession;
301     MemInfoSession mMemInfoSession;
302 
303 public:
handleTx(const hub_message_t * txMsg)304     static int handleTx(const hub_message_t *txMsg) {
305         return getSystem()->doHandleTx(txMsg);
306     }
handleRx(const nano_message * rxMsg)307     static int handleRx(const nano_message *rxMsg) {
308         return getSystem()->doHandleRx(rxMsg);
309     }
310 };
311 
312 }; // namespace nanohub
313 
314 }; // namespace android
315 
316 #endif
317