CHRE: chre_slpi的代码流程

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


slpi上是怎样建立一个环境去运行chre

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<Mutex> 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::init()

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<EventLoopManager> EventLoopManagerSingleton;

//! Extern the explicit EventLoopManagerSingleton to force non-inline method
//! calls. This reduces codesize considerably.
extern template class Singleton<EventLoopManager>;

使用模板类Singleton管理EventLoopManager,并且给这个赋值的模板起了个别名EventLoopManagerSingleton

Singleton

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<typename ObjectType>
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<typename... Args>
  static void init(Args&&... args);

}

namespace chre {

template<typename ObjectType>
typename std::aligned_storage<sizeof(ObjectType), alignof(ObjectType)>::type
    Singleton<ObjectType>::sObject;

template<typename ObjectType>
bool Singleton<ObjectType>::sIsInitialized = false;

template<typename ObjectType>
template<typename... Args>
void Singleton<ObjectType>::init(Args&&... args) {
  if (!sIsInitialized) {
    sIsInitialized = true;
    new (get()) ObjectType(std::forward<Args>(args)...);
  }
}
template<typename ObjectType>
ObjectType *Singleton<ObjectType>::get() {
  return reinterpret_cast<ObjectType *>(&sObject);
}

}

chreThreadEntry
​​​​

到这里就调用了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");
}

 

创建SocketClient 通过socket: chre和slpi_chre通信

实现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的创建和链接

    SocketClient client;
    sp<SocketCallbacks> callbacks = new SocketCallbacks();
    client.connect("chre", callbacks));

1 构造函数

SocketClient::SocketClient() {
  std::atomic_init(&mSockFd, INVALID_SOCKET);
}

2 connect

client.connect("chre", callbacks); //connect到那个server?如何处理server发过来的数据

bool SocketClient::connect(const char *socketName,
                   const sp<ICallbacks>& callbacks) {
return doConnect(socketName, callbacks, false /* connectInBackground */);
}

bool SocketClient::doConnect(const char *socketName,
                     const sp<ICallbacks>& callbacks,
                       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;
}


2.2 receiveThread

 

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::MessageContainerT> container =
          fbs::UnPackMessageContainer(message);
      fbs::ChreMessageUnion& msg = container->message;
  
      switch (container->message.type) {
        case fbs::ChreMessage::NanoappMessage:
          handlers.handleNanoappMessage(*msg.AsNanoappMessage());
          break;
       ---
}

2.3 有关callback的理解

上面是callback的注册到被调用的流程,client创建具体的callbacks函数,client创建recievethread
调用callbacks,并不是server去调用这些callback, callback意思是server触发了(发送数据)callback的调用
但执行体(运行callback的thread)还是client本身

 

requestHubInfo的过程

  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();
  }
 

socket server: chre收到 socket client数据的机制

::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<void(uint16_t clientId, void *data, size_t len)> ClientMessageCallback;        
  
    /** 
     * 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);
  }
}

处理来着client的数据: 进入slpi进行处理,enqueue: gOutboundQueue

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<const unsigned char *>(data), static_cast<int>(length));

    }
}

//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<size_t>(messageLen))) {
      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;
}

chre host怎样得到 gOutboundQueue 中的数据

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<size_t>(messageLen));
      } else {
        server->sendToClientById(messageBuffer,
                                 static_cast<size_t>(messageLen), hostClientId);
      }
    }
}

 

/**
 * 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<size_t>(bufferLen);
    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,其他关联吗?

sendUnloadNanoappRequest的过程

socket client sendUnloadNanoappRequest

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();
}

UnloadNanoappRequest

省略如上类似的过程,直接到slpi decodeMessageFromHost

bool HostProtocolChre::decodeMessageFromHost(const void *message,
                                             size_t messageLen) {
      case fbs::ChreMessage::UnloadNanoappRequest: {
        const auto *request = static_cast<const fbs::UnloadNanoappRequest *>(
            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);
  }
}

//把SystemCallbackType和对应的处理方法、数据放到一个 event里 post


/**
* 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<uint16_t>(type), data, callback,
                         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;
}

哪里处理mEvents

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());
  }

distributeEvent

void EventLoop::distributeEvent(Event *event) {
  for (const UniquePtr<Nanoapp>& app : mNanoapps) {
    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中?
}

deliverEvents

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<Nanoapp>& app : mNanoapps) {
    if (app->hasPendingEvent()) {
      havePendingEvents |= deliverNextEvent(app);
    }
  }

  return havePendingEvents;
}

bool EventLoop::deliverNextEvent(const UniquePtr<Nanoapp>& app) {
  // 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);
}

疑问:EventLoop里把mEvent发送到各个关联的nanoApp,调用对应的handleEvnet,并没有找到调用SystemCallback的地方。

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,
};

handleUnloadNanoappCallback

void handleUnloadNanoappCallback(uint16_t /*eventType*/, void *data) {
  auto msgBuilder = [](FlatBufferBuilder& builder, void *cookie) {
    auto *cbData = static_cast<UnloadNanoappCallbackData *>(cookie);

    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;
}

sendLoadNanoappRequest的过程

sendLoadNanoappRequest

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<uint8_t> buffer(size);
    if (!file.read(reinterpret_cast<char*>(buffer.data()), size)) {
      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<const fbs::LoadNanoappRequest *>(
            container->message());
        const flatbuffers::Vector<uint8_t> *appBinary = request->app_binary();
        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<Nanoapp> nanoapp = sLoadManager.releaseNanoapp();
    auto cbData = MakeUnique<LoadNanoappCallbackData>();
    {
      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<LoadNanoappCallbackData *>(cookie);

    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<Nanoapp>
  UniquePtr<LoadNanoappCallbackData> dataWrapped(
      static_cast<LoadNanoappCallbackData *>(data));
  constexpr size_t kInitialBufferSize = 48;
  buildAndEnqueueMessage(PendingMessageType::LoadNanoappResponse,
                         kInitialBufferSize, msgBuilder, data);
}

bool EventLoop::startNanoapp(UniquePtr<Nanoapp>& nanoapp) {
  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<Mutex> lock(mNanoappsLock);
      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<uint16_t> mRegisteredEvents;
  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<const char *>(mAppBinary),
      static_cast<int>(mAppBinaryLen), RTLD_NOW);
   {
    mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
        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,
    },  
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值