494 lines
17 KiB
C++
494 lines
17 KiB
C++
/*
|
|
* 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 <chrono>
|
|
#include <condition_variable>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <vector>
|
|
|
|
#include <hardware/context_hub.h>
|
|
#include <nanohub/nanohub.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_HAL_APP_MGMT 0x10 // (char cmd, u64 appId, u64 appMsk) -> (int errno, u32 results)
|
|
|
|
#define NANOHUB_HAL_APP_MGMT_START 0
|
|
#define NANOHUB_HAL_APP_MGMT_STOP 1
|
|
#define NANOHUB_HAL_APP_MGMT_UNLOAD 2
|
|
#define NANOHUB_HAL_APP_MGMT_DELETE 3
|
|
|
|
#define NANOHUB_HAL_SYS_MGMT 0x11 // (char cmd) -> (int errno)
|
|
|
|
#define NANOHUB_HAL_SYS_MGMT_ERASE 0
|
|
#define NANOHUB_HAL_SYS_MGMT_REBOOT 1
|
|
|
|
#define NANOHUB_HAL_APP_INFO 0x12
|
|
|
|
#define NANOHUB_HAL_APP_INFO_APPID 0x00
|
|
#define NANOHUB_HAL_APP_INFO_CRC 0x01
|
|
#define NANOHUB_HAL_APP_INFO_TID 0x02
|
|
#define NANOHUB_HAL_APP_INFO_VERSION 0x03
|
|
#define NANOHUB_HAL_APP_INFO_ADDR 0x04
|
|
#define NANOHUB_HAL_APP_INFO_SIZE 0x05
|
|
#define NANOHUB_HAL_APP_INFO_HEAP 0x06
|
|
#define NANOHUB_HAL_APP_INFO_DATA 0x07
|
|
#define NANOHUB_HAL_APP_INFO_BSS 0x08
|
|
#define NANOHUB_HAL_APP_INFO_CHRE_MAJOR 0x09
|
|
#define NANOHUB_HAL_APP_INFO_CHRE_MINOR 0x0A
|
|
#define NANOHUB_HAL_APP_INFO_END 0xFF
|
|
|
|
#define NANOHUB_HAL_SYS_INFO 0x13
|
|
|
|
#define NANOHUB_HAL_SYS_INFO_HEAP_FREE 0x0F
|
|
#define NANOHUB_HAL_SYS_INFO_RAM_SIZE 0x12
|
|
#define NANOHUB_HAL_SYS_INFO_EEDATA_SIZE 0x13
|
|
#define NANOHUB_HAL_SYS_INFO_EEDATA_FREE 0x14
|
|
#define NANOHUB_HAL_SYS_INFO_CODE_SIZE 0x15
|
|
#define NANOHUB_HAL_SYS_INFO_CODE_FREE 0x16
|
|
#define NANOHUB_HAL_SYS_INFO_SHARED_SIZE 0x17
|
|
#define NANOHUB_HAL_SYS_INFO_SHARED_FREE 0x18
|
|
#define NANOHUB_HAL_SYS_INFO_END 0xFF
|
|
|
|
#define NANOHUB_HAL_KEY_INFO 0x14
|
|
#define NANOHUB_HAL_START_UPLOAD 0x16
|
|
#define NANOHUB_HAL_CONT_UPLOAD 0x17
|
|
#define NANOHUB_HAL_FINISH_UPLOAD 0x18
|
|
|
|
#define NANOHUB_HAL_UPLOAD_ACCEPTED 0
|
|
#define NANOHUB_HAL_UPLOAD_WAIT 1
|
|
#define NANOHUB_HAL_UPLOAD_RESEND 2
|
|
#define NANOHUB_HAL_UPLOAD_RESTART 3
|
|
#define NANOHUB_HAL_UPLOAD_CANCEL 4
|
|
#define NANOHUB_HAL_UPLOAD_CANCEL_NO_RETRY 5
|
|
#define NANOHUB_HAL_UPLOAD_NO_SPACE 6
|
|
|
|
#define NANOHUB_APP_NOT_LOADED (-1)
|
|
#define NANOHUB_APP_LOADED (0)
|
|
|
|
#define NANOHUB_UPLOAD_CHUNK_SZ_MAX 64
|
|
#define NANOHUB_MEM_SZ_UNKNOWN 0xFFFFFFFFUL
|
|
#define NANOHUB_TID_UNKNOWN 0xFFFFFFFFUL
|
|
|
|
#define CONTEXT_HUB_START_APPS 8
|
|
|
|
namespace android {
|
|
|
|
namespace nanohub {
|
|
|
|
int system_comms_handle_rx(const nano_message_raw *msg);
|
|
int system_comms_handle_tx(const hub_message_t *outMsg);
|
|
|
|
struct MgmtStatus {
|
|
union {
|
|
uint32_t value;
|
|
struct {
|
|
uint8_t app;
|
|
uint8_t task;
|
|
uint8_t op;
|
|
uint8_t erase;
|
|
} __attribute__((packed));
|
|
};
|
|
} __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 mCmd;
|
|
uint32_t mTransactionId;
|
|
int32_t mStatus;
|
|
explicit NanohubRsp(MessageBuf &buf, uint32_t transactionId, bool chre);
|
|
};
|
|
|
|
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:
|
|
|
|
class AppManager;
|
|
|
|
/*
|
|
* 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, uint32_t transactionId, AppManager &appManager) = 0;
|
|
virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre) = 0;
|
|
virtual int getState() const = 0; // FSM state
|
|
virtual int getStatus() const = 0; // execution status (result code)
|
|
virtual void abort(int32_t) = 0;
|
|
virtual ~ISession() {}
|
|
};
|
|
|
|
class SessionManager;
|
|
|
|
class Session : public ISession {
|
|
friend class SessionManager;
|
|
|
|
mutable std::mutex mDoneMutex; // controls condition and state transitions
|
|
std::condition_variable mDoneCond;
|
|
volatile int mState;
|
|
|
|
protected:
|
|
mutable std::mutex mLock; // serializes message handling
|
|
int32_t mStatus;
|
|
|
|
enum {
|
|
SESSION_INIT = 0,
|
|
SESSION_DONE = 1,
|
|
SESSION_USER = 2,
|
|
};
|
|
|
|
void complete() {
|
|
std::unique_lock<std::mutex> lk(mDoneMutex);
|
|
if (mState != SESSION_DONE) {
|
|
mState = SESSION_DONE;
|
|
lk.unlock();
|
|
mDoneCond.notify_all();
|
|
}
|
|
}
|
|
void abort(int32_t status) {
|
|
std::lock_guard<std::mutex> _l(mLock);
|
|
mStatus = status;
|
|
complete();
|
|
}
|
|
void setState(int state) {
|
|
if (state == SESSION_DONE) {
|
|
complete();
|
|
} else {
|
|
std::lock_guard<std::mutex> _l(mDoneMutex);
|
|
mState = state;
|
|
}
|
|
}
|
|
public:
|
|
Session() { mState = SESSION_INIT; mStatus = -1; }
|
|
int getStatus() const {
|
|
std::lock_guard<std::mutex> _l(mLock);
|
|
return mStatus;
|
|
}
|
|
int wait() {
|
|
std::unique_lock<std::mutex> lk(mDoneMutex);
|
|
bool success = mDoneCond.wait_for(
|
|
lk, std::chrono::seconds(30),
|
|
[this] { return mState == SESSION_DONE; });
|
|
if (!success) {
|
|
ALOGE("Timed out waiting for response");
|
|
}
|
|
return success ? 0 : -1;
|
|
}
|
|
virtual int getState() const override {
|
|
std::lock_guard<std::mutex> _l(mDoneMutex);
|
|
return mState;
|
|
}
|
|
virtual bool isDone() const {
|
|
std::lock_guard<std::mutex> _l(mDoneMutex);
|
|
return mState == SESSION_DONE;
|
|
}
|
|
virtual bool isRunning() const {
|
|
std::lock_guard<std::mutex> _l(mDoneMutex);
|
|
return mState > SESSION_DONE;
|
|
}
|
|
};
|
|
|
|
class AppMgmtSession : public Session {
|
|
enum {
|
|
TRANSFER = SESSION_USER,
|
|
QUERY_START,
|
|
START,
|
|
STOP_TRANSFER,
|
|
FINISH,
|
|
RUN,
|
|
STOP_RUN,
|
|
RUN_FAILED,
|
|
REBOOT,
|
|
ERASE_TRANSFER,
|
|
MGMT,
|
|
INFO,
|
|
};
|
|
uint32_t mCmd; // LOAD_APP, UNLOAD_APP, ENABLE_APP, DISABLE_APP
|
|
uint32_t mResult;
|
|
std::vector<uint8_t> mData;
|
|
uint32_t mLen;
|
|
uint32_t mPos;
|
|
uint32_t mNextPos;
|
|
uint32_t mErrCnt;
|
|
hub_app_name_t mAppName;
|
|
uint32_t mFlashAddr;
|
|
std::vector<hub_app_name_t> mAppList;
|
|
|
|
int setupMgmt(const hub_message_t *appMsg, uint32_t transactionId, uint32_t cmd, AppManager &appManager);
|
|
int handleTransfer(NanohubRsp &rsp, MessageBuf &, AppManager &appManager);
|
|
int handleStopTransfer(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
|
|
int handleQueryStart(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
|
|
int handleStart(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
|
|
int handleFinish(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
|
|
int handleRun(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
|
|
int handleStopRun(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
|
|
int handleReboot(NanohubRsp &rsp, MessageBuf &buf, AppManager &);
|
|
int handleEraseTransfer(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
|
|
int handleMgmt(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
|
|
int handleInfo(NanohubRsp &rsp, MessageBuf &buf, AppManager &appManager);
|
|
public:
|
|
AppMgmtSession() {
|
|
mCmd = 0;
|
|
mResult = 0;
|
|
mPos = 0;
|
|
mLen = 0;
|
|
memset(&mAppName, 0, sizeof(mAppName));
|
|
}
|
|
virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre) override;
|
|
virtual int setup(const hub_message_t *app_msg, uint32_t transactionId, AppManager &appManager) override;
|
|
};
|
|
|
|
class MemInfoSession : public Session {
|
|
public:
|
|
virtual int setup(const hub_message_t *app_msg, uint32_t transactionId, AppManager &) override;
|
|
virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &, bool chre) override;
|
|
};
|
|
|
|
class KeyInfoSession : public Session {
|
|
std::vector<uint8_t> mRsaKeyData;
|
|
uint32_t mKeyNum;
|
|
uint32_t mKeyOffset;
|
|
int requestRsaKeys(uint32_t transactionId);
|
|
public:
|
|
virtual int setup(const hub_message_t *, uint32_t, AppManager &) override;
|
|
virtual int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &, bool chre) override;
|
|
bool haveKeys() const {
|
|
std::lock_guard<std::mutex> _l(mLock);
|
|
return mRsaKeyData.size() > 0 && !isRunning();
|
|
}
|
|
};
|
|
|
|
class AppManager {
|
|
struct AppData {
|
|
uint32_t version, flashUse, ramUse;
|
|
uint32_t tid, crc, flashAddr;
|
|
uint8_t chre_major, chre_minor;
|
|
bool chre, running, loaded;
|
|
|
|
bool cached_start, cached_napp;
|
|
uint32_t cached_version, cached_crc;
|
|
};
|
|
|
|
typedef std::map<uint64_t, std::unique_ptr<AppData>> AppMap;
|
|
|
|
AppMap apps_;
|
|
|
|
public:
|
|
AppManager() {
|
|
restoreApps();
|
|
}
|
|
void dumpAppInfo(std::string &result);
|
|
bool saveApps();
|
|
bool restoreApps();
|
|
bool eraseApps();
|
|
bool writeApp(hub_app_name_t &appName, const uint8_t *data, int32_t len);
|
|
int32_t readApp(hub_app_name_t &appName, void **data);
|
|
bool cmpApp(hub_app_name_t &appName, const uint8_t *data, uint32_t len);
|
|
uint32_t readNanohubAppInfo(MessageBuf &buf);
|
|
void sendAppInfoToApp(uint32_t transactionId);
|
|
int getAppsToStart(std::vector<hub_app_name_t> &apps);
|
|
bool setCachedCrc(hub_app_name_t &appName, uint32_t crc) {
|
|
if (!isAppPresent(appName))
|
|
return false;
|
|
else {
|
|
apps_[appName.id]->cached_napp = true;
|
|
apps_[appName.id]->cached_crc = crc;
|
|
apps_[appName.id]->cached_start = false;
|
|
saveApps();
|
|
return true;
|
|
}
|
|
}
|
|
bool clearCachedApp(hub_app_name_t &appName) {
|
|
if (!isAppPresent(appName))
|
|
return false;
|
|
else {
|
|
apps_[appName.id]->cached_napp = false;
|
|
apps_[appName.id]->cached_start = false;
|
|
saveApps();
|
|
return true;
|
|
}
|
|
}
|
|
bool clearRunning(hub_app_name_t &appName) {
|
|
if (!isAppLoaded(appName))
|
|
return false;
|
|
else {
|
|
apps_[appName.id]->running = false;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool setCachedVersion(hub_app_name_t &appName, uint32_t version) {
|
|
if (!isAppPresent(appName))
|
|
return false;
|
|
else {
|
|
apps_[appName.id]->cached_version = version;
|
|
return true;
|
|
}
|
|
}
|
|
bool setCachedStart(hub_app_name_t &appName, bool start) {
|
|
if (!isAppPresent(appName))
|
|
return false;
|
|
else {
|
|
apps_[appName.id]->cached_start = start;
|
|
saveApps();
|
|
return true;
|
|
}
|
|
}
|
|
bool addNewApp(hub_app_name_t &appName, uint32_t version) {
|
|
if (isAppLoaded(appName))
|
|
return false;
|
|
else
|
|
apps_[appName.id] = std::unique_ptr<AppData>(new AppData);
|
|
apps_[appName.id]->loaded = false;
|
|
apps_[appName.id]->running = false;
|
|
apps_[appName.id]->chre = false;
|
|
apps_[appName.id]->cached_napp = false;
|
|
apps_[appName.id]->cached_version = version;
|
|
return true;
|
|
}
|
|
bool isAppPresent(hub_app_name_t &appName) {
|
|
return apps_.count(appName.id) != 0;
|
|
}
|
|
bool isAppLoaded(hub_app_name_t &appName) {
|
|
return apps_.count(appName.id) != 0 && apps_[appName.id]->loaded;
|
|
}
|
|
bool isAppRunning(hub_app_name_t &appName) {
|
|
return apps_.count(appName.id) != 0 && apps_[appName.id]->running;
|
|
}
|
|
uint32_t getFlashAddr(hub_app_name_t &appName) {
|
|
if (isAppPresent(appName))
|
|
return apps_[appName.id]->flashAddr;
|
|
else
|
|
return 0xFFFFFFFF;
|
|
}
|
|
};
|
|
|
|
class SessionManager {
|
|
typedef std::map<int, Session* > SessionMap;
|
|
|
|
std::mutex lock;
|
|
SessionMap sessions_;
|
|
|
|
bool isActive(const SessionMap::iterator &pos) const
|
|
{
|
|
return !pos->second->isDone();
|
|
}
|
|
void next(SessionMap::iterator &pos)
|
|
{
|
|
isActive(pos) ? pos++ : pos = sessions_.erase(pos);
|
|
}
|
|
|
|
public:
|
|
int handleRx(MessageBuf &buf, uint32_t transactionId, AppManager &appManager, bool chre, bool &reboot, uint32_t &rebootStatus);
|
|
int setup_and_add(int id, Session *session, const hub_message_t *appMsg, uint32_t transactionId, AppManager &appManager);
|
|
} mSessions;
|
|
|
|
const hub_app_name_t mHostIfAppName = {
|
|
.id = APP_ID_MAKE(NANOHUB_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, uint32_t transactionId);
|
|
int doHandleRx(uint64_t appId, uint32_t transactionId, const char *data, int len, bool chre);
|
|
void doDumpAppInfo(std::string &result);
|
|
|
|
int doHandleRx(const nano_message_raw *rxMsg) {
|
|
return doHandleRx(rxMsg->hdr.appId, 0, reinterpret_cast<const char*>(rxMsg->data), rxMsg->hdr.len, false);
|
|
}
|
|
|
|
int doHandleRx(const nano_message_chre *rxMsg) {
|
|
return doHandleRx(rxMsg->hdr.appId, rxMsg->hdr.appEventId, reinterpret_cast<const char*>(rxMsg->data), rxMsg->hdr.len, true);
|
|
}
|
|
|
|
static void sendToApp(uint32_t typ, uint32_t transactionId, const void *data, uint32_t len) {
|
|
if (NanoHub::messageTracingEnabled()) {
|
|
dumpBuffer("HAL -> APP", get_hub_info()->os_app_name, transactionId, 0, data, len);
|
|
}
|
|
NanoHub::sendToApp(HubMessage(&get_hub_info()->os_app_name, typ, transactionId, ENDPOINT_BROADCAST, data, len));
|
|
}
|
|
static int sendToSystem(const void *data, size_t len, uint32_t transactionId);
|
|
|
|
KeyInfoSession mKeySession;
|
|
AppMgmtSession mAppMgmtSession;
|
|
MemInfoSession mMemInfoSession;
|
|
AppManager mAppManager;
|
|
|
|
public:
|
|
static int handleTx(const hub_message_t *txMsg, uint32_t transactionId) {
|
|
return getSystem()->doHandleTx(txMsg, transactionId);
|
|
}
|
|
static int handleRx(const nano_message_raw *rxMsg) {
|
|
return getSystem()->doHandleRx(rxMsg);
|
|
}
|
|
static int handleRx(const nano_message_chre *rxMsg) {
|
|
return getSystem()->doHandleRx(rxMsg);
|
|
}
|
|
static void dumpAppInfo(std::string &result) {
|
|
return getSystem()->doDumpAppInfo(result);
|
|
}
|
|
};
|
|
|
|
}; // namespace nanohub
|
|
|
|
}; // namespace android
|
|
|
|
#endif
|