Home | History | Annotate | Download | only in contexthubhal
      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)
    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 
    135         void complete() {
    136             Mutex::Autolock _l(mDoneLock);
    137             if (mState != SESSION_DONE) {
    138                 mState = SESSION_DONE;
    139                 mDoneWait.broadcast();
    140             }
    141         }
    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:
    151         Session() { mState = SESSION_INIT; mStatus = -1; }
    152         int getStatus() const {
    153             Mutex::Autolock _l(mLock);
    154             return mStatus;
    155         }
    156         int wait() {
    157             Mutex::Autolock _l(mDoneLock);
    158             while (mState != SESSION_DONE) {
    159                 mDoneWait.wait(mDoneLock);
    160             }
    161             return 0;
    162         }
    163         virtual int getState() const override {
    164             Mutex::Autolock _l(mDoneLock);
    165             return mState;
    166         }
    167         virtual bool isDone() const {
    168             Mutex::Autolock _l(mDoneLock);
    169             return mState == SESSION_DONE;
    170         }
    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:
    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;
    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 
    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:
    254         SessionManager() {
    255             mGlobal.setup(nullptr);
    256         }
    257         int handleRx(MessageBuf &buf);
    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 
    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 
    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:
    304     static int handleTx(const hub_message_t *txMsg) {
    305         return getSystem()->doHandleTx(txMsg);
    306     }
    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