Table of Contents
slpi上是怎样建立一个环境去运行chre
chre::init()
Singleton
chreThreadEntry
创建SocketClient 通过socket: chre和slpi_chre通信
socketClient的创建和链接
1 构造函数
2 connect
2.2 receiveThread
2.3 有关callback的理解
requestHubInfo的过程
socket server: chre收到 socket client数据的机制
处理来着client的数据: 进入slpi进行处理,enqueue: gOutboundQueue
chre host怎样得到 gOutboundQueue 中的数据
sendUnloadNanoappRequest的过程
socket client sendUnloadNanoappRequest
UnloadNanoappRequest
//把SystemCallbackType和对应的处理方法、数据放到一个 event里 post
哪里处理mEvents
distributeEvent
deliverEvents
疑问:EventLoop里把mEvent发送到各个关联的nanoApp,调用对应的handleEvnet,并没有找到调用SystemCallback的地方。
handleUnloadNanoappCallback
sendLoadNanoappRequest的过程
sendLoadNanoappRequest
chre/host/msm/daemon/chre_daemon.cc
main -> chre_slpi_start_thread()
chre/platform/slpi/init.cc
/**
* Invoked over FastRPC to initialize and start the CHRE thread.
*
* @return 0 on success, nonzero on failure (per FastRPC requirements)
*/
extern "C" int chre_slpi_start_thread(void) {
// This lock ensures that we only start the thread once
LockGuard lock(gThreadMutex);
int fastRpcResult = CHRE_FASTRPC_ERROR;
{
// This must complete before we can receive messages that might result in
// posting an event
chre::init();
// Human-readable name for the CHRE thread (not const in QuRT API, but they
// make a copy)
char threadName[] = "CHRE";
qurt_thread_attr_t attributes;
qurt_thread_attr_init(&attributes);
qurt_thread_attr_set_name(&attributes, threadName);
qurt_thread_attr_set_priority(&attributes, kThreadPriority);
qurt_thread_attr_set_stack_addr(&attributes, &gStack);
qurt_thread_attr_set_stack_size(&attributes, kStackSize);
qurt_thread_attr_set_tcb_partition(&attributes, kTcbPartition);
gThreadRunning = true;
LOGI("Starting CHRE thread");
int result = qurt_thread_create(&gThreadHandle, &attributes,
chreThreadEntry, nullptr);
{
LOGD("Started CHRE thread");
fastRpcResult = CHRE_FASTRPC_SUCCESS;
}
}
return fastRpcResult;
}
chre的代码里充斥了大量的 EventLoopManagerSingleton::get(), EventLoopManagerSingleton应该是是一个全局唯一的对象,哪里创建了这个对象?
这里通过init()就创建了全局对象EventLoopManagerSingleton, 为什么init会创建对象?通过Singleton类实现
在文件//chre/core/include/chre/core/event_loop_manager.h找到了EventLoopManagerSingleton的相关定义
/**
* A class that keeps track of all event loops in the system. This class
* represents the top-level object in CHRE. It will own all resources that are
* shared by all event loops.
*/
class EventLoopManager : public NonCopyable {
//! The event loop managed by this event loop manager.
EventLoop mEventLoop;
//---
}
//! Provide an alias to the EventLoopManager singleton.
typedef Singleton
//! Extern the explicit EventLoopManagerSingleton to force non-inline method
//! calls. This reduces codesize considerably.
extern template class Singleton
使用模板类Singleton管理EventLoopManager,并且给这个赋值的模板起了个别名EventLoopManagerSingleton
Singleton的关键是通过init()创建对象,通过get()获得对象,
/**
* The Singleton template provides static storage for one instance of the
* provided type. Initialization does not happen automatically which allows
* users of this API to control the order of initialization.
*/
template
class Singleton : public NonCopyable {
public:
/**
* Constructs the object in the space provided by this container. If the
* object is already constructed, no operation is performed. Use the
* isInitialized method to determine if construction is required.
*
* @param args The constructor arguments to pass to the singleton instance.
*/
template
static void init(Args&&... args);
}
namespace chre {
template
typename std::aligned_storage::type
Singleton::sObject;
template
bool Singleton::sIsInitialized = false;
template
template
void Singleton::init(Args&&... args) {
if (!sIsInitialized) {
sIsInitialized = true;
new (get()) ObjectType(std::forward(args)...);
}
}
template
ObjectType *Singleton::get() {
return reinterpret_cast(&sObject);
}
}
到这里就调用了EventLoopd的run函数去处理event.
/**
* Entry point for the QuRT thread that runs CHRE.
*
* @param data Argument passed to qurt_thread_create()
*/
void chreThreadEntry(void * /*data*/) {
EventLoopManagerSingleton::get()->lateInit();
chre::loadStaticNanoapps();
chre::loadPreloadedNanoapps();
ashRegisterDebugDumpCallback("CHRE", onDebugDumpRequested, nullptr);
EventLoopManagerSingleton::get()->getEventLoop().run();
ashUnregisterDebugDumpCallback(onDebugDumpRequested);
chre::deinit();
gThreadRunning = false;
LOGD("CHRE thread exiting");
}
实现socketClinet的关键是实现
class SocketCallbacks : public SocketClient::ICallbacks, public IChreMessageHandlers {
}
其中SocketClient::ICallbacks
//host/common/include/chre_host/socket_client.h
class SocketClient {
public:
SocketClient();
~SocketClient();
/**
* Represents the callback interface used for handling events that occur on
* the receive thread. Note that it is *not* safe to call connect(),
* connectInBackground(), or disconnect() from the context of these callbacks.
*/
class ICallbacks : public VirtualLightRefBase {
public:
/**
* Invoked from within the context of the read thread when a message is
* received on the socket.
*
* @param data Buffer containing received message data
* @param length Size of the message in bytes
*/
virtual void onMessageReceived(const void *data, size_t length) = 0;
/**
* Called when the socket is successfully (re-)connected.
*/
virtual void onConnected() {};
/**
* Called when we have failed to (re-)connect the socket after many attempts
* and are giving up.
*/
virtual void onConnectionAborted() {};
/**
* Invoked when the socket is disconnected, and this connection loss was not
* the result of an explicit call to disconnect(), i.e. the connection was
* terminated on the remote end.
*/
virtual void onDisconnected() {};
};
}
其中IChreMessageHandlers
//host/common/include/chre_host/host_protocol_host.h
/**
* Calling code should provide an implementation of this interface to handle
* parsed results from decodeMessageFromChre().
*/
class IChreMessageHandlers {
public:
virtual ~IChreMessageHandlers() = default;
virtual void handleNanoappMessage(const ::chre::fbs::NanoappMessageT& /*message*/) {};
virtual void handleHubInfoResponse(const ::chre::fbs::HubInfoResponseT& /*response*/) {};
virtual void handleNanoappListResponse(const ::chre::fbs::NanoappListResponseT& /*response*/) {};
virtual void handleLoadNanoappResponse(const ::chre::fbs::LoadNanoappResponseT& /*response*/) {};
virtual void handleUnloadNanoappResponse(const ::chre::fbs::UnloadNanoappResponseT& /*response*/) {};
virtual void handleDebugDumpData(const ::chre::fbs::DebugDumpDataT& /*data*/) {};
virtual void handleDebugDumpResponse(const ::chre::fbs::DebugDumpResponseT& /*response*/) {};
};
SocketClient client;
sp
client.connect("chre", callbacks));
SocketClient::SocketClient() {
std::atomic_init(&mSockFd, INVALID_SOCKET);
}
client.connect("chre", callbacks); //connect到那个server?如何处理server发过来的数据
bool SocketClient::connect(const char *socketName,
const sp
return doConnect(socketName, callbacks, false /* connectInBackground */);
}
bool SocketClient::doConnect(const char *socketName,
const sp
bool connectInBackground) {
tryConnect()
mCallbacks = callbacks;
mRxThread = std::thread([this]() {
receiveThread();
});
return success;
}
2.1 . create socket
bool SocketClient::tryConnect(bool suppressErrorLogs) {
bool success = false;
int sockFd = socket(AF_LOCAL, SOCK_SEQPACKET, 0);
// Set the send buffer size to 2MB to allow plenty of room for nanoapp
// loading
int sndbuf = 2 * 1024 * 1024;
int ret = setsockopt(
sockFd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(sndbuf));
if (ret == 0) {
mSockFd = socket_local_client_connect(
sockFd, mSocketName, ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
}
return success;
}
void SocketClient::receiveThread() {
constexpr size_t kReceiveBufferSize = 4096;
uint8_t buffer[kReceiveBufferSize];
//在receiveThread中接收收据并进行处理
while (!mGracefulShutdown && (mSockFd != INVALID_SOCKET || reconnect())) {
ssize_t bytesReceived = recv(mSockFd, buffer, sizeof(buffer), 0);
mCallbacks->onMessageReceived(buffer, bytesReceived);
}
}
}
void onMessageReceived(const void* data, size_t length) override
{
if (!HostProtocolHost::decodeMessageFromChre(data, length, *this)) {
LOGE("Failed to decode message");
}
}
函数的原型是:
static bool decodeMessageFromChre(const void *message, size_t messageLen,
IChreMessageHandlers& handlers);
而上面的this是个执行对象SocketCallbacks的指针
//这里*this表示取指针的内容,且SocketCallbacks继承自IChreMessageHandlers,所有类型没有问题
bool HostProtocolHost::decodeMessageFromChre( //通过this指针的传递,把具体的实现传入
const void *message, size_t messageLen, IChreMessageHandlers& handlers) {
bool success = verifyMessage(message, messageLen);
if (success) {
std::unique_ptr
fbs::UnPackMessageContainer(message);
fbs::ChreMessageUnion& msg = container->message;
switch (container->message.type) {
case fbs::ChreMessage::NanoappMessage:
handlers.handleNanoappMessage(*msg.AsNanoappMessage());
break;
---
}
上面是callback的注册到被调用的流程,client创建具体的callbacks函数,client创建recievethread
调用callbacks,并不是server去调用这些callback, callback意思是server触发了(发送数据)callback的调用
但执行体(运行callback的thread)还是client本身
int requestHubInfo(SocketClient& client)
{
FlatBufferBuilder builder(64); //数据的传输协议是flatbuffer
HostProtocolHost::encodeHubInfoRequest(builder);
LOGI("Sending hub info request (%" PRIu32 " bytes)", builder.GetSize());
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
LOGE("Failed to send message");
}
return waitForResponse();
}
::android::chre::SocketServer server;
start_thread(&msg_to_host_thread, chre_message_to_host_thread, &server));
server.run("chre", true, onMessageReceivedFromClient);
/**
* Start a thread with default attributes, or log an error on failure
*
* @return bool true if the thread was successfully started
*/
static bool start_thread(pthread_t *thread_handle,
thread_entry_point_f *thread_entry,
void *arg) {
int ret = pthread_create(thread_handle, NULL, thread_entry, arg);
if (ret != 0) {
LOG_ERROR("pthread_create failed", ret);
}
return (ret == 0);
}
class SocketServer {
public:
SocketServer();
/**
* Defines the function signature of the callback given to run() which
* receives message data sent in by a client.
*
* @param clientId A unique identifier for the client that sent this request
* (assigned locally)
* @param data Pointer to buffer containing the raw message data
* @param len Number of bytes of data received
*/
typedef std::function
/**
* Opens the socket, and runs the receive loop until an error is encountered,
* or SIGINT/SIGTERM is received. Masks off all other signals.
*
* @param socketName Android socket name to use when listening
* @param allowSocketCreation If true, allow creation of the socket rather
* than strictly inheriting it from init (used primarily for
* development purposes)
* @param clientMessageCallback Callback to be invoked when a message is
* received from a client
*/
void run(const char *socketName, bool allowSocketCreation,
ClientMessageCallback clientMessageCallback);
}
创建命名chre socket server
void SocketServer::run(const char *socketName, bool allowSocketCreation,
ClientMessageCallback clientMessageCallback) {
mClientMessageCallback = clientMessageCallback;//下面会用到mClientMessageCallback
mSockFd = socket_local_server(socketName,
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
int ret = listen(mSockFd, kMaxPendingConnectionRequests);//监听来着clinet的数据
{
serviceSocket();
}
close(mSockFd);
}
void SocketServer::serviceSocket() {
LOGI("Ready to accept connections");
while (!sSignalReceived) {
int ret = ppoll(mPollFds, 1 + kMaxActiveClients, nullptr, &signalMask);
if (mPollFds[kListenIndex].revents & POLLIN) {
acceptClientConnection();
}
for (size_t i = 1; i <= kMaxActiveClients; i++) {
if (mPollFds[i].revents & POLLIN) {
handleClientData(mPollFds[i].fd);
}
}
}
}
void SocketServer::handleClientData(int clientSocket) {
const ClientData& clientData = mClients[clientSocket];
uint16_t clientId = clientData.clientId;
ssize_t packetSize = recv(
clientSocket, mRecvBuffer.data(), mRecvBuffer.size(), MSG_DONTWAIT);
LOGV("Got %zd byte packet from client %" PRIu16, packetSize, clientId);
mClientMessageCallback(clientId, mRecvBuffer.data(), packetSize);
}
}
mClientMessageCallback(clientId, mRecvBuffer.data(), packetSize);
mClientMessageCallback就是onMessageReceivedFromClient
void onMessageReceivedFromClient(uint16_t clientId, void *data, size_t length) {
constexpr size_t kMaxPayloadSize = 1024 * 1024; // 1 MiB
int ret = chre_slpi_deliver_message_from_host(
static_cast
}
}
//platform/slpi/host_link.cc, 进入了slpi的世界
extern "C" int chre_slpi_deliver_message_from_host(const unsigned char *message,
int messageLen) {
if (!HostProtocolChre::decodeMessageFromHost(
message, static_cast
LOGE("Failed to decode/handle message");
} else {
result = CHRE_FASTRPC_SUCCESS;
}
return result;
}
bool HostProtocolChre::decodeMessageFromHost(const void *message,
size_t messageLen) {
case fbs::ChreMessage::HubInfoRequest:
HostMessageHandlers::handleHubInfoRequest(hostClientId);
break;
}
void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
// We generate the response in the context of chre_slpi_get_message_to_host
LOGD("Got hub info request from client ID %" PRIu16, hostClientId);
enqueueMessage(PendingMessage(
PendingMessageType::HubInfoResponse, hostClientId));
}
//PendingMessage(PendingMessageType::HubInfoResponse, hostClientId)的构造函数
struct PendingMessage {
PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
type = msgType;
data.hostClientId = hostClientId;
}
//--- ---
PendingMessageType type;
union {
const MessageToHost *msgToHost;
uint16_t hostClientId;
FlatBufferBuilder *builder;
} data;
}
//访问 enum class成员的方法: PendingMessageType::HubInfoResponse
enum class PendingMessageType {
Shutdown,
NanoappMessageToHost,
HubInfoResponse,
NanoappListResponse,
LoadNanoappResponse,
UnloadNanoappResponse,
DebugDumpData,
DebugDumpResponse,
TimeSyncRequest,
LowPowerMicAccessRequest,
LowPowerMicAccessRelease,
};
/**
* Wrapper function to enqueue a message on the outbound message queue. All
* outgoing message to the host must be called through this function.
*
* @param message The message to send to host.
*
* @return true if the message was successfully added to the queue.
*/
bool enqueueMessage(PendingMessage message) {
// Vote for big image temporarily when waking up the main thread waiting for
// the message
bool voteSuccess = slpiForceBigImage();
bool success = gOutboundQueue.push(message);
// Remove the vote only if we successfully made a big image transition
if (voteSuccess) {
slpiRemoveBigImageVote();
}
return success;
}
start_thread(&msg_to_host_thread, chre_message_to_host_thread, &server));
//放到queue就可以了吗?哪里把他取出来?
//想不到竟然在host/msm/daemon/chre_daemon.cc中
/**
* Entry point for the thread that receives messages sent by CHRE.
*
* @return always returns NULL
*/
static void *chre_message_to_host_thread(void *arg) {
unsigned char messageBuffer[4096];
unsigned int messageLen;
int result = 0;
auto *server = static_cast<::android::chre::SocketServer *>(arg);
while (true) {
messageLen = 0;
LOGV("Calling into chre_slpi_get_message_to_host");
result = chre_slpi_get_message_to_host(
messageBuffer, sizeof(messageBuffer), &messageLen);
} else if (result == CHRE_FASTRPC_SUCCESS && messageLen > 0) {
uint16_t hostClientId;
fbs::ChreMessage messageType;
if (!HostProtocolHost::extractHostClientIdAndType(
messageBuffer, messageLen, &hostClientId, &messageType)) {
LOGW("Failed to extract host client ID from message - sending "
"broadcast");
hostClientId = chre::kHostClientIdUnspecified;
}
if (hostClientId == chre::kHostClientIdUnspecified) {
server->sendToAllClients(messageBuffer,
static_cast
} else {
server->sendToClientById(messageBuffer,
static_cast
}
}
}
/**
* FastRPC method invoked by the host to block on messages
*
* @param buffer Output buffer to populate with message data
* @param bufferLen Size of the buffer, in bytes
* @param messageLen Output parameter to populate with the size of the message
* in bytes upon success
*
* @return 0 on success, nonzero on failure
*/
extern "C" int chre_slpi_get_message_to_host(
unsigned char *buffer, int bufferLen, unsigned int *messageLen) {
{
size_t bufferSize = static_cast
PendingMessage pendingMsg = gOutboundQueue.pop(); //从gOutboundQueue中取出
switch (pendingMsg.type) {
case PendingMessageType::Shutdown:
result = CHRE_FASTRPC_ERROR_SHUTTING_DOWN;
break;
case PendingMessageType::NanoappMessageToHost:
result = generateMessageToHost(pendingMsg.data.msgToHost, buffer,
bufferSize, messageLen);
break;
case PendingMessageType::HubInfoResponse:
result = generateHubInfoResponse(pendingMsg.data.hostClientId, buffer,
bufferSize, messageLen);
break;
case PendingMessageType::NanoappListResponse:
case PendingMessageType::LoadNanoappResponse:
case PendingMessageType::UnloadNanoappResponse:
case PendingMessageType::DebugDumpData:
case PendingMessageType::DebugDumpResponse:
case PendingMessageType::TimeSyncRequest:
case PendingMessageType::LowPowerMicAccessRequest:
case PendingMessageType::LowPowerMicAccessRelease:
result = generateMessageFromBuilder(pendingMsg.data.builder,
buffer, bufferSize, messageLen);
break;
default:
CHRE_ASSERT_LOG(false, "Unexpected pending message type");
}
return result;
}
int generateHubInfoResponse(uint16_t hostClientId, unsigned char *buffer,
size_t bufferSize, unsigned int *messageLen) {
constexpr size_t kInitialBufferSize = 192;
constexpr char kHubName[] = "CHRE on SLPI";
constexpr char kVendor[] = "Google";
constexpr char kToolchain[] = "Hexagon Tools 8.x (clang "
STRINGIFY(__clang_major__) "."
STRINGIFY(__clang_minor__) "."
STRINGIFY(__clang_patchlevel__) ")";
constexpr uint32_t kLegacyPlatformVersion = 0;
constexpr uint32_t kLegacyToolchainVersion =
((__clang_major__ & 0xFF) << 24) |
((__clang_minor__ & 0xFF) << 16) |
(__clang_patchlevel__ & 0xFFFF);
constexpr float kPeakMips = 350;
constexpr float kStoppedPower = 0;
constexpr float kSleepPower = 1;
constexpr float kPeakPower = 15;
// Note that this may execute prior to EventLoopManager::lateInit() completing
FlatBufferBuilder builder(kInitialBufferSize);
HostProtocolChre::encodeHubInfoResponse(
builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion,
kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower,
kPeakPower, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(),
chreGetVersion(), hostClientId);
return copyToHostBuffer(builder, buffer, bufferSize, messageLen);
}
到此chre client 请求HubInfo到得到HubInfo的过程就完成了。这个过程并没有关联EventLoop,其他关联吗?
int sendUnloadNanoappRequest(SocketClient& client, uint64_t appId)
{
FlatBufferBuilder builder(48);
constexpr uint32_t kTransactionId = 4321;
HostProtocolHost::encodeUnloadNanoappRequest(
builder, kTransactionId, appId, true /* allowSystemNanoappUnload */);
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
LOGE("Failed to send message");
}
return waitForResponse();
}
省略如上类似的过程,直接到slpi decodeMessageFromHost
bool HostProtocolChre::decodeMessageFromHost(const void *message,
size_t messageLen) {
case fbs::ChreMessage::UnloadNanoappRequest: {
const auto *request = static_cast(
container->message());
HostMessageHandlers::handleUnloadNanoappRequest(
hostClientId, request->transaction_id(), request->app_id(),
request->allow_system_nanoapp_unload());
break;
}
}
转化成deferCallback
void HostMessageHandlers::handleUnloadNanoappRequest(
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
bool allowSystemNanoappUnload) {
auto *cbData = memoryAlloc<UnloadNanoappCallbackData>();
{
cbData->appId = appId;
cbData->transactionId = transactionId;
cbData->hostClientId = hostClientId;
cbData->allowSystemNanoappUnload = allowSystemNanoappUnload;
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::HandleUnloadNanoapp, cbData,
handleUnloadNanoappCallback);
}
}
/**
* Leverages the event queue mechanism to schedule a CHRE system callback to
* be invoked at some point in the future from within the context of the
* "main" EventLoop. Which EventLoop is considered to be the "main" one is
* currently not specified, but it is required to be exactly one EventLoop
* that does not change at runtime.
*
* This function is safe to call from any thread.
*
* @param type An identifier for the callback, which is passed through to the
* callback as a uint16_t, and can also be useful for debugging
* @param data Arbitrary data to provide to the callback
* @param callback Function to invoke from within the
*/
void deferCallback(SystemCallbackType type, void *data,
SystemCallbackFunction *callback) {
mEventLoop.postEvent(static_cast
kSystemInstanceId, kSystemInstanceId);
}
bool EventLoop::postEvent(uint16_t eventType, void *eventData,
chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
uint32_t targetInstanceId) {
if (mRunning && (senderInstanceId == kSystemInstanceId ||
mEventPool.getFreeBlockCount() > kMinReservedSystemEventCount)) {
success = allocateAndPostEvent(eventType, eventData, freeCallback,
senderInstanceId,targetInstanceId);
}
return success;
}
bool EventLoop::allocateAndPostEvent(uint16_t eventType, void *eventData,
chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
uint32_t targetInstanceId) {
bool success = false;
Event *event = mEventPool.allocate(eventType, eventData, freeCallback,
senderInstanceId, targetInstanceId);
if (event != nullptr) {
success = mEvents.push(event);
}
return success;
}
void EventLoop::run() {
bool havePendingEvents = false;
while (mRunning) {
// Events are delivered in two stages: first they arrive in the inbound
// event queue mEvents (potentially posted from another thread), then within
// this context these events are distributed to smaller event queues
// associated with each Nanoapp that should receive the event. Once the
// event is delivered to all interested Nanoapps, its free callback is
// invoked.
if (!havePendingEvents || !mEvents.empty()) {
if (mEvents.size() > mMaxEventPoolUsage) {
mMaxEventPoolUsage = mEvents.size();
}
// mEvents.pop() will be a blocking call if mEvents.empty()
distributeEvent(mEvents.pop());
}
havePendingEvents = deliverEvents();
mPowerControlManager.postEventLoopProcess(mEvents.size());
}
void EventLoop::distributeEvent(Event *event) {
for (const UniquePtr
if ((event->targetInstanceId == chre::kBroadcastInstanceId
&& app->isRegisteredForBroadcastEvent(event->eventType))
|| event->targetInstanceId == app->getInstanceId()) {
app->postEvent(event);
}
}
if (event->isUnreferenced()) {
// Events sent to the system instance ID are processed via the free callback
// and are not expected to be delivered to any nanoapp, so no need to log a
// warning in that case
if (event->senderInstanceId != kSystemInstanceId) {
LOGW("Dropping event 0x%" PRIx16, event->eventType);
}
freeEvent(event);
}
}
void Nanoapp::postEvent(Event *event) {
mEventQueue.push(event);//把event加入到每个Nanoapp中?
}
bool EventLoop::deliverEvents() {
bool havePendingEvents = false;
// Do one loop of round-robin. We might want to have some kind of priority or
// time sharing in the future, but this should be good enough for now.
for (const UniquePtr
if (app->hasPendingEvent()) {
havePendingEvents |= deliverNextEvent(app);
}
}
return havePendingEvents;
}
bool EventLoop::deliverNextEvent(const UniquePtr
// TODO: cleaner way to set/clear this? RAII-style?
mCurrentApp = app.get();
Event *event = app->processNextEvent();
mCurrentApp = nullptr;
if (event->isUnreferenced()) {
freeEvent(event);
}
return app->hasPendingEvent();
}
Event *Nanoapp::processNextEvent() {
Event *event = mEventQueue.pop();
CHRE_ASSERT_LOG(event != nullptr, "Tried delivering event, but queue empty");
if (event != nullptr) {
handleEvent(event->senderInstanceId, event->eventType, event->eventData);
}
return event;
}
void PlatformNanoapp::handleEvent(uint32_t senderInstanceId,
uint16_t eventType,
const void *eventData) {
mAppInfo->entryPoints.handleEvent(senderInstanceId, eventType, eventData);
}
enum class SystemCallbackType : uint16_t {
FirstCallbackType = CHRE_EVENT_FIRST_USER_VALUE,
MessageToHostComplete,
WifiScanMonitorStateChange,
WifiRequestScanResponse,
WifiHandleScanEvent,
NanoappListResponse,
SensorLastEventUpdate,
FinishLoadingNanoapp,
WwanHandleCellInfoResult,
HandleUnloadNanoapp,
GnssSessionStatusChange,
SensorStatusUpdate,
PerformDebugDump,
TimerPoolTick,
AudioHandleDataEvent,
WifiHandleFailedRanging,
WifiHandleRangingEvent,
AudioAvailabilityChange,
};
void handleUnloadNanoappCallback(uint16_t /*eventType*/, void *data) {
auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
auto *cbData = static_cast
bool success = false;
uint32_t instanceId;
EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
if (!eventLoop.findNanoappInstanceIdByAppId(cbData->appId, &instanceId)) {
LOGE("Couldn't unload app ID 0x%016" PRIx64 ": not found", cbData->appId);
} else {
success = eventLoop.unloadNanoapp(instanceId,
cbData->allowSystemNanoappUnload);
}
HostProtocolChre::encodeUnloadNanoappResponse(
builder, cbData->hostClientId, cbData->transactionId, success);
};
constexpr size_t kInitialBufferSize = 52;
buildAndEnqueueMessage(PendingMessageType::UnloadNanoappResponse,
kInitialBufferSize, msgBuilder, data);
memoryFree(data);
}
//chre/core/event_loop.cc
bool EventLoop::unloadNanoapp(uint32_t instanceId,
bool allowSystemNanoappUnload) {
bool unloaded = false;
for (size_t i = 0; i < mNanoapps.size(); i++) {
if (instanceId == mNanoapps[i]->getInstanceId()) {
if (!allowSystemNanoappUnload && mNanoapps[i]->isSystemNanoapp()) {
LOGE("Refusing to unload system nanoapp");
} else {
// Make sure all messages sent by this nanoapp at least have their
// associated free callback processing pending in the event queue (i.e.
// there are no messages pending delivery to the host)
EventLoopManagerSingleton::get()->getHostCommsManager()
.flushMessagesSentByNanoapp(mNanoapps[i]->getAppId());
// Distribute all inbound events we have at this time - here we're
// interested in handling any message free callbacks generated by
// flushMessagesSentByNanoapp()
flushInboundEventQueue();
// Mark that this nanoapp is stopping early, so it can't send events or
// messages during the nanoapp event queue flush
mStoppingNanoapp = mNanoapps[i].get();
// Process any pending events, with the intent of ensuring that we free
// all events generated by this nanoapp
flushNanoappEventQueues();
// Post the unload event now (so we can reference the Nanoapp instance
// directly), but nanoapps won't get it until after the unload completes
notifyAppStatusChange(CHRE_EVENT_NANOAPP_STOPPED, *mStoppingNanoapp);
// Finally, we are at a point where there should not be any pending
// events or messages sent by the app that could potentially reference
// the nanoapp's memory, so we are safe to unload it
unloadNanoappAtIndex(i);
mStoppingNanoapp = nullptr;
// TODO: right now we assume that the nanoapp will clean up all of its
// resource allocations in its nanoappEnd callback (memory, sensor
// subscriptions, etc.), otherwise we're leaking resources. We should
// perform resource cleanup automatically here to avoid these types of
// potential leaks.
LOGD("Unloaded nanoapp with instanceId %" PRIu32, instanceId);
unloaded = true;
}
break;
}
}
return unloaded;
}
int sendLoadNanoappRequest(
SocketClient& client, const char* filename, uint64_t appId,
uint32_t appVersion)
{
std::ifstream file(filename, std::ios::binary | std::ios::ate);
ssize_t size = file.tellg();
file.seekg(0, std::ios::beg);
std::vector
if (!file.read(reinterpret_cast
LOGE("Couldn't read from file: %s", strerror(errno));
return 0;
}
//android::chre::FragmentedLoadRequest request = android::chre::FragmentedLoadRequest(0,1,appId, appVersion, 0x01000000,size, buffer);
const android::chre::FragmentedLoadRequest &rrequest(android::chre::FragmentedLoadRequest(0,1,appId, appVersion, 0x01000000,size, buffer));
FlatBufferBuilder builder(128 + rrequest.binary.size());
HostProtocolHost::encodeFragmentedLoadNanoappRequest(builder, rrequest);
if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
LOGE("Failed to send message");
}
return waitForResponse();
}
case fbs::ChreMessage::LoadNanoappRequest: {
const auto *request = static_cast
container->message());
const flatbuffers::Vector
HostMessageHandlers::handleLoadNanoappRequest(
hostClientId, request->transaction_id(), request->app_id(),
request->app_version(), request->target_api_version(),
appBinary->data(), appBinary->size(), request->fragment_id(),
request->total_app_size());
break;
}
void HostMessageHandlers::handleLoadNanoappRequest(
uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
uint32_t appVersion, uint32_t targetApiVersion, const void *buffer,
size_t bufferLen, uint32_t fragmentId, size_t appBinaryLen) {
UniquePtr
auto cbData = MakeUnique
{
cbData->transactionId = transactionId;
cbData->hostClientId = hostClientId;
cbData->appId = appId;
cbData->fragmentId = fragmentId;
cbData->nanoapp = std::move(nanoapp);
// Note that if this fails, we'll generate the error response in
// the normal deferred callback
EventLoopManagerSingleton::get()->deferCallback(
SystemCallbackType::FinishLoadingNanoapp, cbData.release(),
finishLoadingNanoappCallback);
}
}
void finishLoadingNanoappCallback(uint16_t /*eventType*/, void *data) {
auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
auto *cbData = static_cast
EventLoop& eventLoop = EventLoopManagerSingleton::get()->getEventLoop();
bool success =
cbData->nanoapp->isLoaded() && eventLoop.startNanoapp(cbData->nanoapp);
HostProtocolChre::encodeLoadNanoappResponse(
builder, cbData->hostClientId, cbData->transactionId,
success, cbData->fragmentId);
};
// Re-wrap the callback data struct, so it is destructed and freed, ensuring
// we don't leak the embedded UniquePtr
UniquePtr
static_cast
constexpr size_t kInitialBufferSize = 48;
buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse,
kInitialBufferSize, msgBuilder, data);
}
bool EventLoop::startNanoapp(UniquePtr
CHRE_ASSERT(!nanoapp.isNull());
bool success = false;
auto *eventLoopManager = EventLoopManagerSingleton::get();
EventLoop& eventLoop = eventLoopManager->getEventLoop();
uint32_t existingInstanceId;
{
nanoapp->setInstanceId(eventLoopManager->getNextInstanceId());
LOGD("Instance ID %" PRIu32 " assigned to app ID 0x%016" PRIx64,
nanoapp->getInstanceId(), nanoapp->getAppId());
Nanoapp *newNanoapp = nanoapp.get();
{
LockGuard
mNanoapps.push_back(std::move(nanoapp));
// After this point, nanoapp is null as we've transferred ownership into
// mNanoapps.back() - use newNanoapp to reference it
}
mCurrentApp = newNanoapp;
success = newNanoapp->start();
mCurrentApp = nullptr;
if (!success) {
} else {
notifyAppStatusChange(CHRE_EVENT_NANOAPP_STARTED, *newNanoapp);
}
}
return success;
}
//chre/core/event_loop.cc
#include "chre/core/nanoapp.h"
/**
* A class that tracks the state of a Nanoapp including incoming events and
* event registrations.
*
* Inheritance is used to separate the common interface with common
* implementation part (chre::Nanoapp) from the common interface with
* platform-specific implementation part (chre::PlatformNanoapp) from the purely
* platform-specific part (chre::PlatformNanoappBase). However, this inheritance
* relationship does *not* imply polymorphism, and this object must only be
* referred to via the most-derived type, i.e. chre::Nanoapp.
*/
class Nanoapp : public PlatformNanoapp {
private:
DynamicVector
EventRefQueue mEventQueue;
}
//chre/platform/include/chre/platform/platform_nanoapp.h
/**
* The common interface to Nanoapp functionality that has platform-specific
* implementation but must be supported for every platform.
*/
class PlatformNanoapp : public PlatformNanoappBase, public NonCopyable {
}
//chre/platform/slpi/include/chre/target_platform/platform_nanoapp_base.h
/**
* SLPI-specific nanoapp functionality.
*/
class PlatformNanoappBase {
public:
/**
* Reserves buffer space for a nanoapp's binary. This method should be called
* before copyNanoappFragment is called.
*
* @param appId The unique app identifier associated with this binary
* @param appVersion An application-defined version number
* @param appBinaryLen Size of appBinary, in bytes
*
* @return true if the allocation was successful, false otherwise
*/
bool reserveBuffer(uint64_t appId, uint32_t appVersion, size_t appBinarylen);
}
bool PlatformNanoapp::start() {
// Invoke the start entry point after successfully opening the app
if (!isUimgApp()) {
slpiForceBigImage();
}
return openNanoapp() && mAppInfo->entryPoints.start();
}
bool PlatformNanoappBase::openNanoapp() {
bool success = false;
if (mIsStatic) {
success = true;
} else if (mFilename != nullptr) {
success = openNanoappFromFile();
} else if (mAppBinary != nullptr) {
success = openNanoappFromBuffer();
} else {
CHRE_ASSERT(false);
}
// Save this flag locally since it may be referenced while the system is in
// micro-image
if (mAppInfo != nullptr) {
mIsUimgApp = mAppInfo->isTcmNanoapp;
}
return success;
}
bool PlatformNanoappBase::openNanoappFromBuffer() {
bool success = false;
// Populate a filename string (just a requirement of the dlopenbuf API)
constexpr size_t kMaxFilenameLen = 17;
char filename[kMaxFilenameLen];
snprintf(filename, sizeof(filename), "%016" PRIx64, mExpectedAppId);
mDsoHandle = dlopenbuf(
filename, static_cast
static_cast
{
mAppInfo = static_cast
dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
if (mAppInfo == nullptr) {
LOGE("Failed to find app info symbol: %s", dlerror());
} else {
success = validateAppInfo(mExpectedAppId, mExpectedAppVersion, mAppInfo);
if (!success) {
mAppInfo = nullptr;
} else {
LOGI("Successfully loaded nanoapp: %s (0x%016" PRIx64 ") version 0x%"
PRIx32 " uimg %d system %d", mAppInfo->name, mAppInfo->appId,
mAppInfo->appVersion, mAppInfo->isTcmNanoapp,
mAppInfo->isSystemNanoapp);
memoryFreeBigImage(mAppBinary);
mAppBinary = nullptr;
}
}
}
return success;
}
//! The symbol name expected from the nanoapp's definition of its info struct
#define CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME "_chreNslDsoNanoappInfo"
//chre/platform/shared/include/chre/platform/shared/nanoapp_support_lib_dso.h
/**
* DSO-based nanoapps must expose this struct under a symbol whose name is given
* by CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME. When the nanoapp is loaded, dlsym()
* will be used to locate this symbol to register the nanoapp with the system.
*/
struct chreNslNanoappInfo {
//! @see CHRE_NSL_NANOAPP_INFO_MAGIC
uint32_t magic;
//! @see CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION
uint8_t structMinorVersion;
//! Set to 1 if this nanoapp is a "system nanoapp" that should not show up in
//! the context hub HAL, likely because it implements some device
//! functionality beneath the HAL.
uint8_t isSystemNanoapp:1;
//! Set to 1 if this nanoapp runs in tightly coupled memory. This flag is only
//! relevant to platforms that have the ability to run nanoapps within tightly
//! coupled memory.
//!
//! @since minor version 1
uint8_t isTcmNanoapp:1;
//! Reserved for future use, set to 0. Assignment of this field to some use
//! must be accompanied by an increase of the struct minor version.
uint8_t reservedFlags:6;
uint8_t reserved;
//! The CHRE API version that the nanoapp was compiled against
uint32_t targetApiVersion;
//! A human-friendly name of the nanoapp vendor (null-terminated string,
//! maximum length CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN)
const char *vendor;
//! A human-friendly name for the nanoapp (null-terminated string, maximum
//! length CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN)
const char *name;
//! Identifies the vendor (most significant 5 bytes) and application
uint64_t appId;
//! Application-specific version number
uint32_t appVersion;
struct {
chreNanoappStartFunction *start;
chreNanoappHandleEventFunction *handleEvent;
chreNanoappEndFunction *end;
} entryPoints;
};
DLL_EXPORT const struct chreNslNanoappInfo _chreNslDsoNanoappInfo = {
.magic = CHRE_NSL_NANOAPP_INFO_MAGIC,
.structMinorVersion = CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION,
.targetApiVersion = CHRE_API_VERSION,
// These values are supplied by the build environment
.vendor = NANOAPP_VENDOR_STRING,
>> .name = NANOAPP_NAME_STRING,
.isSystemNanoapp = 0,
>> .appId = NANOAPP_ID,
>> .appVersion = NANOAPP_VERSION,
.entryPoints = {
>> .start = nanoappStart,
>> .handleEvent = nanoappHandleEvent,
>> .end = nanoappEnd,
},
};