200 lines
5.8 KiB
C++
200 lines
5.8 KiB
C++
|
|
/*
|
||
|
|
* Copyright (C) 2022 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.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#include "chre/util/pigweed/rpc_server.h"
|
||
|
|
|
||
|
|
#include <cinttypes>
|
||
|
|
#include <cstdint>
|
||
|
|
|
||
|
|
#include "chre/util/nanoapp/log.h"
|
||
|
|
#include "chre/util/pigweed/rpc_helper.h"
|
||
|
|
#include "chre_api/chre.h"
|
||
|
|
|
||
|
|
#ifndef LOG_TAG
|
||
|
|
#define LOG_TAG "[RpcServer]"
|
||
|
|
#endif // LOG_TAG
|
||
|
|
|
||
|
|
namespace chre {
|
||
|
|
|
||
|
|
RpcServer::~RpcServer() {
|
||
|
|
chreConfigureNanoappInfoEvents(false);
|
||
|
|
// TODO(b/251257328): Disable all notifications at once.
|
||
|
|
while (!mConnectedHosts.empty()) {
|
||
|
|
chreConfigureHostEndpointNotifications(mConnectedHosts[0], false);
|
||
|
|
mConnectedHosts.erase(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool RpcServer::registerServices(size_t numServices,
|
||
|
|
RpcServer::Service *services) {
|
||
|
|
// Avoid blowing up the stack with chreServices.
|
||
|
|
constexpr size_t kMaxServices = 8;
|
||
|
|
|
||
|
|
if (numServices > kMaxServices) {
|
||
|
|
LOGE("Can not register more than %zu services at once", kMaxServices);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
chreNanoappRpcService chreServices[kMaxServices];
|
||
|
|
|
||
|
|
for (size_t i = 0; i < numServices; ++i) {
|
||
|
|
const Service &service = services[i];
|
||
|
|
|
||
|
|
if (mServer.IsServiceRegistered(service.service)) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
chreServices[i] = {
|
||
|
|
.id = service.id,
|
||
|
|
.version = service.version,
|
||
|
|
};
|
||
|
|
|
||
|
|
mServer.RegisterService(service.service);
|
||
|
|
}
|
||
|
|
|
||
|
|
return chrePublishRpcServices(chreServices, numServices);
|
||
|
|
}
|
||
|
|
|
||
|
|
void RpcServer::setPermissionForNextMessage(uint32_t permission) {
|
||
|
|
mPermission.set(permission);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool RpcServer::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
|
||
|
|
const void *eventData) {
|
||
|
|
switch (eventType) {
|
||
|
|
case CHRE_EVENT_MESSAGE_FROM_HOST:
|
||
|
|
return handleMessageFromHost(eventData);
|
||
|
|
case ChreChannelOutputBase::PW_RPC_CHRE_NAPP_REQUEST_EVENT_TYPE:
|
||
|
|
return handleMessageFromNanoapp(senderInstanceId, eventData);
|
||
|
|
case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION:
|
||
|
|
handleHostClientNotification(eventData);
|
||
|
|
return true;
|
||
|
|
case CHRE_EVENT_NANOAPP_STOPPED:
|
||
|
|
handleNanoappStopped(eventData);
|
||
|
|
return true;
|
||
|
|
default:
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool RpcServer::handleMessageFromHost(const void *eventData) {
|
||
|
|
auto *hostMessage = static_cast<const chreMessageFromHostData *>(eventData);
|
||
|
|
|
||
|
|
if (hostMessage->messageType !=
|
||
|
|
ChreChannelOutputBase::PW_RPC_CHRE_HOST_MESSAGE_TYPE) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
pw::span packet(static_cast<const std::byte *>(hostMessage->message),
|
||
|
|
hostMessage->messageSize);
|
||
|
|
|
||
|
|
pw::Result<uint32_t> result = pw::rpc::ExtractChannelId(packet);
|
||
|
|
if (result.status() != PW_STATUS_OK) {
|
||
|
|
LOGE("Unable to extract channel ID from packet");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!validateHostChannelId(hostMessage, result.value())) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!chreConfigureHostEndpointNotifications(hostMessage->hostEndpoint,
|
||
|
|
true)) {
|
||
|
|
LOGW("Fail to register for host client updates");
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t hostIndex = mConnectedHosts.find(hostMessage->hostEndpoint);
|
||
|
|
if (hostIndex == mConnectedHosts.size()) {
|
||
|
|
mConnectedHosts.push_back(hostMessage->hostEndpoint);
|
||
|
|
}
|
||
|
|
|
||
|
|
mHostOutput.setHostEndpoint(hostMessage->hostEndpoint);
|
||
|
|
mServer.OpenChannel(result.value(), mHostOutput);
|
||
|
|
|
||
|
|
pw::Status status = mServer.ProcessPacket(packet);
|
||
|
|
|
||
|
|
if (status != pw::OkStatus()) {
|
||
|
|
LOGE("Failed to process the packet");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
// TODO(b/242301032): factor code with handleMessageFromHost
|
||
|
|
bool RpcServer::handleMessageFromNanoapp(uint32_t senderInstanceId,
|
||
|
|
const void *eventData) {
|
||
|
|
const auto data = static_cast<const ChrePigweedNanoappMessage *>(eventData);
|
||
|
|
pw::span packet(static_cast<const std::byte *>(data->msg), data->msgSize);
|
||
|
|
|
||
|
|
pw::Result<uint32_t> result = pw::rpc::ExtractChannelId(packet);
|
||
|
|
if (result.status() != PW_STATUS_OK) {
|
||
|
|
LOGE("Unable to extract channel ID from packet");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!validateNanoappChannelId(senderInstanceId, result.value())) {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
chreConfigureNanoappInfoEvents(true);
|
||
|
|
|
||
|
|
mNanoappOutput.setClient(senderInstanceId);
|
||
|
|
mServer.OpenChannel(result.value(), mNanoappOutput);
|
||
|
|
|
||
|
|
pw::Status success = mServer.ProcessPacket(packet);
|
||
|
|
|
||
|
|
if (success != pw::OkStatus()) {
|
||
|
|
LOGE("Failed to process the packet");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
void RpcServer::handleHostClientNotification(const void *eventData) {
|
||
|
|
if (mConnectedHosts.empty()) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
auto notif =
|
||
|
|
static_cast<const struct chreHostEndpointNotification *>(eventData);
|
||
|
|
|
||
|
|
if (notif->notificationType == HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT) {
|
||
|
|
size_t hostIndex = mConnectedHosts.find(notif->hostEndpointId);
|
||
|
|
if (hostIndex != mConnectedHosts.size()) {
|
||
|
|
mServer.CloseChannel(kChannelIdHostClient |
|
||
|
|
static_cast<uint32_t>(notif->hostEndpointId));
|
||
|
|
mConnectedHosts.erase(hostIndex);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
void RpcServer::handleNanoappStopped(const void *eventData) {
|
||
|
|
auto info = static_cast<const struct chreNanoappInfo *>(eventData);
|
||
|
|
|
||
|
|
if (info->instanceId > kRpcNanoappMaxId) {
|
||
|
|
LOGE("Invalid nanoapp Id 0x%08" PRIx32, info->instanceId);
|
||
|
|
} else {
|
||
|
|
mServer.CloseChannel(info->instanceId);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
pw::Status RpcServer::closeChannel(uint32_t id) {
|
||
|
|
return mServer.CloseChannel(id);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace chre
|