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 
     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;
    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 
    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         }
    155         void abort(int32_t status) {
    156             std::lock_guard<std::mutex> _l(mLock);
    157             mStatus = status;
    158             complete();
    159         }
    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:
    169         Session() { mState = SESSION_INIT; mStatus = -1; }
    170         int getStatus() const {
    171             std::lock_guard<std::mutex> _l(mLock);
    172             return mStatus;
    173         }
    174         int wait() {
    175             std::unique_lock<std::mutex> lk(mDoneMutex);
    176             mDoneCond.wait(lk, [this] { return mState == SESSION_DONE; });
    177             return 0;
    178         }
    179         virtual int getState() const override {
    180             std::lock_guard<std::mutex> _l(mDoneMutex);
    181             return mState;
    182         }
    183         virtual bool isDone() const {
    184             std::lock_guard<std::mutex> _l(mDoneMutex);
    185             return mState == SESSION_DONE;
    186         }
    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:
    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;
    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 
    260         bool isActive(const SessionMap::iterator &pos) const
    261         {
    262             return !pos->second->isDone();
    263         }
    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 
    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(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:
    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