| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef _NANOHUB_SYSTEM_COMMS_H_ |
| #define _NANOHUB_SYSTEM_COMMS_H_ |
| |
| #include <utils/Condition.h> |
| #include <utils/Mutex.h> |
| |
| #include <map> |
| #include <vector> |
| |
| #include <hardware/context_hub.h> |
| #include "nanohubhal.h" |
| #include "message_buf.h" |
| |
| //rx: return 0 if handled, > 0 if not handled, < 0 if error happened |
| |
| #define MSG_HANDLED 0 |
| |
| //messages to the HostIf nanoapp & their replies (mesages and replies both begin with u8 message_type) |
| #define NANOHUB_EXT_APPS_ON 0 // () -> (char success) |
| #define NANOHUB_EXT_APPS_OFF 1 // () -> (char success) |
| #define NANOHUB_EXT_APP_DELETE 2 // (u64 name) -> (char success) //idempotent |
| #define NANOHUB_QUERY_MEMINFO 3 // () -> (mem_info) |
| #define NANOHUB_QUERY_APPS 4 // (u32 idxStart) -> (app_info[idxStart] OR EMPTY IF NO MORE) |
| #define NANOHUB_QUERY_RSA_KEYS 5 // (u32 byteOffset) -> (u8 data[1 or more bytes] OR EMPTY IF NO MORE) |
| #define NANOHUB_START_UPLOAD 6 // (char isOs, u32 totalLenToTx) -> (char success) |
| #define NANOHUB_CONT_UPLOAD 7 // (u32 offset, u8 data[]) -> (char success) |
| #define NANOHUB_FINISH_UPLOAD 8 // () -> (char success) |
| #define NANOHUB_REBOOT 9 // () -> (char success) |
| |
| // Custom defined private messages |
| #define CONTEXT_HUB_LOAD_OS (CONTEXT_HUB_TYPE_PRIVATE_MSG_BASE + 1) |
| |
| |
| #define NANOHUB_APP_NOT_LOADED (-1) |
| #define NANOHUB_APP_LOADED (0) |
| |
| #define NANOHUB_UPLOAD_CHUNK_SZ_MAX 64 |
| #define NANOHUB_MEM_SZ_UNKNOWN 0xFFFFFFFFUL |
| |
| namespace android { |
| |
| namespace nanohub { |
| |
| int system_comms_handle_rx(const nano_message *msg); |
| int system_comms_handle_tx(const hub_message_t *outMsg); |
| |
| struct NanohubAppInfo { |
| hub_app_name_t name; |
| uint32_t version, flashUse, ramUse; |
| } __attribute__((packed)); |
| |
| struct NanohubMemInfo { |
| //sizes |
| uint32_t flashSz, blSz, osSz, sharedSz, eeSz; |
| uint32_t ramSz; |
| |
| //use |
| uint32_t blUse, osUse, sharedUse, eeUse; |
| uint32_t ramUse; |
| } __attribute__((packed)); |
| |
| struct NanohubRsp { |
| uint32_t cmd; |
| int32_t status; |
| NanohubRsp(MessageBuf &buf, bool no_status = false); |
| }; |
| |
| inline bool operator == (const hub_app_name_t &a, const hub_app_name_t &b) { |
| return a.id == b.id; |
| } |
| |
| inline bool operator != (const hub_app_name_t &a, const hub_app_name_t &b) { |
| return !(a == b); |
| } |
| |
| class SystemComm { |
| private: |
| |
| /* |
| * Nanohub HAL sessions |
| * |
| * Session is an object that can group several message exchanges with FW, |
| * maintain state, and be waited for completion by someone else. |
| * |
| * As of this moment, since all sessions are triggered by client thread, |
| * and all the exchange is happening in local worker thread, it is only possible |
| * for client thread to wait on session completion. |
| * Allowing sessions to wait on each other will require a worker thread pool. |
| * It is now unnecessary, and not implemented. |
| */ |
| class ISession { |
| public: |
| virtual int setup(const hub_message_t *app_msg) = 0; |
| virtual int handleRx(MessageBuf &buf) = 0; |
| virtual int getState() const = 0; // FSM state |
| virtual int getStatus() const = 0; // execution status (result code) |
| virtual ~ISession() {} |
| }; |
| |
| class SessionManager; |
| |
| class Session : public ISession { |
| friend class SessionManager; |
| |
| mutable Mutex mDoneLock; // controls condition and state transitions |
| Condition mDoneWait; |
| volatile int mState; |
| |
| protected: |
| mutable Mutex mLock; // serializes message handling |
| int32_t mStatus; |
| |
| enum { |
| SESSION_INIT = 0, |
| SESSION_DONE = 1, |
| SESSION_USER = 2, |
| }; |
| |
| void complete() { |
| Mutex::Autolock _l(mDoneLock); |
| if (mState != SESSION_DONE) { |
| mState = SESSION_DONE; |
| mDoneWait.broadcast(); |
| } |
| } |
| void setState(int state) { |
| if (state == SESSION_DONE) { |
| complete(); |
| } else { |
| Mutex::Autolock _l(mDoneLock); |
| mState = state; |
| } |
| } |
| public: |
| Session() { mState = SESSION_INIT; mStatus = -1; } |
| int getStatus() const { |
| Mutex::Autolock _l(mLock); |
| return mStatus; |
| } |
| int wait() { |
| Mutex::Autolock _l(mDoneLock); |
| while (mState != SESSION_DONE) { |
| mDoneWait.wait(mDoneLock); |
| } |
| return 0; |
| } |
| virtual int getState() const override { |
| Mutex::Autolock _l(mDoneLock); |
| return mState; |
| } |
| virtual bool isDone() const { |
| Mutex::Autolock _l(mDoneLock); |
| return mState == SESSION_DONE; |
| } |
| virtual bool isRunning() const { |
| Mutex::Autolock _l(mDoneLock); |
| return mState > SESSION_DONE; |
| } |
| }; |
| |
| class AppMgmtSession : public Session { |
| enum { |
| TRANSFER = SESSION_USER, |
| FINISH, |
| RELOAD, |
| REBOOT, |
| MGMT, |
| }; |
| uint32_t mCmd; // UPLOAD_APP | UPPLOAD_OS |
| uint32_t mResult; |
| std::vector<uint8_t> mData; |
| uint32_t mLen; |
| uint32_t mPos; |
| |
| int setupMgmt(const hub_message_t *appMsg, uint32_t cmd); |
| int handleTransfer(NanohubRsp &rsp); |
| int handleFinish(NanohubRsp &rsp); |
| int handleReload(NanohubRsp &rsp); |
| int handleReboot(NanohubRsp &rsp); |
| int handleMgmt(NanohubRsp &rsp); |
| public: |
| AppMgmtSession() { |
| mCmd = 0; |
| mResult = 0; |
| mPos = 0; |
| mLen = 0; |
| } |
| virtual int handleRx(MessageBuf &buf) override; |
| virtual int setup(const hub_message_t *app_msg) override; |
| }; |
| |
| class MemInfoSession : public Session { |
| public: |
| virtual int setup(const hub_message_t *app_msg) override; |
| virtual int handleRx(MessageBuf &buf) override; |
| }; |
| |
| class KeyInfoSession : public Session { |
| std::vector<uint8_t> mRsaKeyData; |
| int requestRsaKeys(void); |
| public: |
| virtual int setup(const hub_message_t *) override; |
| virtual int handleRx(MessageBuf &buf) override; |
| bool haveKeys() const { |
| Mutex::Autolock _l(mLock); |
| return mRsaKeyData.size() > 0 && !isRunning(); |
| } |
| }; |
| |
| class AppInfoSession : public Session { |
| std::vector<hub_app_info> mAppInfo; |
| int requestNext(); |
| public: |
| virtual int setup(const hub_message_t *) override; |
| virtual int handleRx(MessageBuf &buf) override; |
| }; |
| |
| class GlobalSession : public Session { |
| public: |
| virtual int setup(const hub_message_t *) override; |
| virtual int handleRx(MessageBuf &buf) override; |
| }; |
| |
| class SessionManager { |
| typedef std::map<int, Session* > SessionMap; |
| |
| Mutex lock; |
| SessionMap sessions_; |
| GlobalSession mGlobal; |
| |
| void next(SessionMap::iterator &pos) |
| { |
| Mutex::Autolock _l(lock); |
| pos->second->isDone() ? pos = sessions_.erase(pos) : ++pos; |
| } |
| |
| public: |
| SessionManager() { |
| mGlobal.setup(nullptr); |
| } |
| int handleRx(MessageBuf &buf); |
| int setup_and_add(int id, Session *session, const hub_message_t *appMsg) { |
| Mutex::Autolock _l(lock); |
| if (sessions_.count(id) == 0 && !session->isRunning()) { |
| int ret = session->setup(appMsg); |
| if (ret < 0) { |
| session->complete(); |
| } else { |
| sessions_[id] = session; |
| } |
| return ret; |
| } |
| return -EBUSY; |
| } |
| |
| } mSessions; |
| |
| const hub_app_name_t mHostIfAppName = { |
| .id = NANO_APP_ID(NANOAPP_VENDOR_GOOGLE, 0) |
| }; |
| |
| static SystemComm *getSystem() { |
| // this is thread-safe in c++11 |
| static SystemComm theInstance; |
| return &theInstance; |
| } |
| |
| SystemComm () = default; |
| ~SystemComm() = default; |
| |
| int doHandleTx(const hub_message_t *txMsg); |
| int doHandleRx(const nano_message *rxMsg); |
| |
| static void sendToApp(uint32_t typ, const void *data, uint32_t len) { |
| if (NanoHub::messageTracingEnabled()) { |
| dumpBuffer("HAL -> APP", get_hub_info()->os_app_name, typ, data, len); |
| } |
| NanoHub::sendToApp(&get_hub_info()->os_app_name, typ, data, len); |
| } |
| static int sendToSystem(const void *data, size_t len); |
| |
| KeyInfoSession mKeySession; |
| AppMgmtSession mAppMgmtSession; |
| AppInfoSession mAppInfoSession; |
| MemInfoSession mMemInfoSession; |
| |
| public: |
| static int handleTx(const hub_message_t *txMsg) { |
| return getSystem()->doHandleTx(txMsg); |
| } |
| static int handleRx(const nano_message *rxMsg) { |
| return getSystem()->doHandleRx(rxMsg); |
| } |
| }; |
| |
| }; // namespace nanohub |
| |
| }; // namespace android |
| |
| #endif |