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