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