1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker * Copyright (C) 2022 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker *
4*84e33947SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker *
8*84e33947SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker *
10*84e33947SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker */
16*84e33947SAndroid Build Coastguard Worker
17*84e33947SAndroid Build Coastguard Worker #include "chre/util/pigweed/rpc_server.h"
18*84e33947SAndroid Build Coastguard Worker
19*84e33947SAndroid Build Coastguard Worker #include <cinttypes>
20*84e33947SAndroid Build Coastguard Worker #include <cstdint>
21*84e33947SAndroid Build Coastguard Worker
22*84e33947SAndroid Build Coastguard Worker #include "chre/util/nanoapp/log.h"
23*84e33947SAndroid Build Coastguard Worker #include "chre/util/pigweed/rpc_helper.h"
24*84e33947SAndroid Build Coastguard Worker #include "chre_api/chre.h"
25*84e33947SAndroid Build Coastguard Worker #include "pw_status/status.h"
26*84e33947SAndroid Build Coastguard Worker
27*84e33947SAndroid Build Coastguard Worker #ifndef LOG_TAG
28*84e33947SAndroid Build Coastguard Worker #define LOG_TAG "[RpcServer]"
29*84e33947SAndroid Build Coastguard Worker #endif // LOG_TAG
30*84e33947SAndroid Build Coastguard Worker
31*84e33947SAndroid Build Coastguard Worker namespace chre {
32*84e33947SAndroid Build Coastguard Worker
registerServices(size_t numServices,RpcServer::Service * services)33*84e33947SAndroid Build Coastguard Worker bool RpcServer::registerServices(size_t numServices,
34*84e33947SAndroid Build Coastguard Worker RpcServer::Service *services) {
35*84e33947SAndroid Build Coastguard Worker // Avoid blowing up the stack with chreServices.
36*84e33947SAndroid Build Coastguard Worker constexpr size_t kMaxServices = 8;
37*84e33947SAndroid Build Coastguard Worker
38*84e33947SAndroid Build Coastguard Worker if (numServices > kMaxServices) {
39*84e33947SAndroid Build Coastguard Worker LOGE("Can not register more than %zu services at once", kMaxServices);
40*84e33947SAndroid Build Coastguard Worker return false;
41*84e33947SAndroid Build Coastguard Worker }
42*84e33947SAndroid Build Coastguard Worker
43*84e33947SAndroid Build Coastguard Worker chreNanoappRpcService chreServices[kMaxServices];
44*84e33947SAndroid Build Coastguard Worker
45*84e33947SAndroid Build Coastguard Worker for (size_t i = 0; i < numServices; ++i) {
46*84e33947SAndroid Build Coastguard Worker const Service &service = services[i];
47*84e33947SAndroid Build Coastguard Worker
48*84e33947SAndroid Build Coastguard Worker if (mServer.IsServiceRegistered(service.service)) {
49*84e33947SAndroid Build Coastguard Worker return false;
50*84e33947SAndroid Build Coastguard Worker }
51*84e33947SAndroid Build Coastguard Worker
52*84e33947SAndroid Build Coastguard Worker chreServices[i] = {
53*84e33947SAndroid Build Coastguard Worker .id = service.id,
54*84e33947SAndroid Build Coastguard Worker .version = service.version,
55*84e33947SAndroid Build Coastguard Worker };
56*84e33947SAndroid Build Coastguard Worker
57*84e33947SAndroid Build Coastguard Worker mServer.RegisterService(service.service);
58*84e33947SAndroid Build Coastguard Worker }
59*84e33947SAndroid Build Coastguard Worker
60*84e33947SAndroid Build Coastguard Worker return chrePublishRpcServices(chreServices, numServices);
61*84e33947SAndroid Build Coastguard Worker }
62*84e33947SAndroid Build Coastguard Worker
setPermissionForNextMessage(uint32_t permission)63*84e33947SAndroid Build Coastguard Worker void RpcServer::setPermissionForNextMessage(uint32_t permission) {
64*84e33947SAndroid Build Coastguard Worker mPermission.set(permission);
65*84e33947SAndroid Build Coastguard Worker }
66*84e33947SAndroid Build Coastguard Worker
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)67*84e33947SAndroid Build Coastguard Worker bool RpcServer::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
68*84e33947SAndroid Build Coastguard Worker const void *eventData) {
69*84e33947SAndroid Build Coastguard Worker switch (eventType) {
70*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_MESSAGE_FROM_HOST:
71*84e33947SAndroid Build Coastguard Worker return handleMessageFromHost(eventData);
72*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_RPC_REQUEST:
73*84e33947SAndroid Build Coastguard Worker return handleMessageFromNanoapp(senderInstanceId, eventData);
74*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION:
75*84e33947SAndroid Build Coastguard Worker handleHostClientNotification(eventData);
76*84e33947SAndroid Build Coastguard Worker return true;
77*84e33947SAndroid Build Coastguard Worker case CHRE_EVENT_NANOAPP_STOPPED:
78*84e33947SAndroid Build Coastguard Worker handleNanoappStopped(eventData);
79*84e33947SAndroid Build Coastguard Worker return true;
80*84e33947SAndroid Build Coastguard Worker default:
81*84e33947SAndroid Build Coastguard Worker return true;
82*84e33947SAndroid Build Coastguard Worker }
83*84e33947SAndroid Build Coastguard Worker }
84*84e33947SAndroid Build Coastguard Worker
close()85*84e33947SAndroid Build Coastguard Worker void RpcServer::close() {
86*84e33947SAndroid Build Coastguard Worker chreConfigureNanoappInfoEvents(false);
87*84e33947SAndroid Build Coastguard Worker // TODO(b/251257328): Disable all notifications at once.
88*84e33947SAndroid Build Coastguard Worker while (!mConnectedHosts.empty()) {
89*84e33947SAndroid Build Coastguard Worker chreConfigureHostEndpointNotifications(mConnectedHosts[0], false);
90*84e33947SAndroid Build Coastguard Worker mConnectedHosts.erase(0);
91*84e33947SAndroid Build Coastguard Worker }
92*84e33947SAndroid Build Coastguard Worker }
93*84e33947SAndroid Build Coastguard Worker
handleMessageFromHost(const void * eventData)94*84e33947SAndroid Build Coastguard Worker bool RpcServer::handleMessageFromHost(const void *eventData) {
95*84e33947SAndroid Build Coastguard Worker auto *hostMessage = static_cast<const chreMessageFromHostData *>(eventData);
96*84e33947SAndroid Build Coastguard Worker
97*84e33947SAndroid Build Coastguard Worker if (hostMessage->messageType != CHRE_MESSAGE_TYPE_RPC) {
98*84e33947SAndroid Build Coastguard Worker return false;
99*84e33947SAndroid Build Coastguard Worker }
100*84e33947SAndroid Build Coastguard Worker
101*84e33947SAndroid Build Coastguard Worker pw::span packet(static_cast<const std::byte *>(hostMessage->message),
102*84e33947SAndroid Build Coastguard Worker hostMessage->messageSize);
103*84e33947SAndroid Build Coastguard Worker
104*84e33947SAndroid Build Coastguard Worker pw::Result<uint32_t> result = pw::rpc::ExtractChannelId(packet);
105*84e33947SAndroid Build Coastguard Worker if (!result.status().ok()) {
106*84e33947SAndroid Build Coastguard Worker LOGE("Unable to extract channel ID from packet: %" PRIu8,
107*84e33947SAndroid Build Coastguard Worker static_cast<uint8_t>(result.status().code()));
108*84e33947SAndroid Build Coastguard Worker return false;
109*84e33947SAndroid Build Coastguard Worker }
110*84e33947SAndroid Build Coastguard Worker
111*84e33947SAndroid Build Coastguard Worker if (!validateHostChannelId(hostMessage, result.value())) {
112*84e33947SAndroid Build Coastguard Worker return false;
113*84e33947SAndroid Build Coastguard Worker }
114*84e33947SAndroid Build Coastguard Worker
115*84e33947SAndroid Build Coastguard Worker if (!chreConfigureHostEndpointNotifications(hostMessage->hostEndpoint,
116*84e33947SAndroid Build Coastguard Worker true)) {
117*84e33947SAndroid Build Coastguard Worker LOGW("Fail to register for host client updates");
118*84e33947SAndroid Build Coastguard Worker }
119*84e33947SAndroid Build Coastguard Worker
120*84e33947SAndroid Build Coastguard Worker size_t hostIndex = mConnectedHosts.find(hostMessage->hostEndpoint);
121*84e33947SAndroid Build Coastguard Worker if (hostIndex == mConnectedHosts.size()) {
122*84e33947SAndroid Build Coastguard Worker mConnectedHosts.push_back(hostMessage->hostEndpoint);
123*84e33947SAndroid Build Coastguard Worker }
124*84e33947SAndroid Build Coastguard Worker
125*84e33947SAndroid Build Coastguard Worker mHostOutput.setHostEndpoint(hostMessage->hostEndpoint);
126*84e33947SAndroid Build Coastguard Worker pw::Status status = mServer.OpenChannel(result.value(), mHostOutput);
127*84e33947SAndroid Build Coastguard Worker if (status != pw::OkStatus() && status != pw::Status::AlreadyExists()) {
128*84e33947SAndroid Build Coastguard Worker LOGE("Failed to open channel: %" PRIu8, static_cast<uint8_t>(status.code()));
129*84e33947SAndroid Build Coastguard Worker return false;
130*84e33947SAndroid Build Coastguard Worker }
131*84e33947SAndroid Build Coastguard Worker
132*84e33947SAndroid Build Coastguard Worker status = mServer.ProcessPacket(packet);
133*84e33947SAndroid Build Coastguard Worker if (!status.ok()) {
134*84e33947SAndroid Build Coastguard Worker LOGE("Failed to process the packet: %" PRIu8, static_cast<uint8_t>(status.code()));
135*84e33947SAndroid Build Coastguard Worker return false;
136*84e33947SAndroid Build Coastguard Worker }
137*84e33947SAndroid Build Coastguard Worker
138*84e33947SAndroid Build Coastguard Worker return true;
139*84e33947SAndroid Build Coastguard Worker }
140*84e33947SAndroid Build Coastguard Worker
141*84e33947SAndroid Build Coastguard Worker // TODO(b/242301032): factor code with handleMessageFromHost
handleMessageFromNanoapp(uint32_t senderInstanceId,const void * eventData)142*84e33947SAndroid Build Coastguard Worker bool RpcServer::handleMessageFromNanoapp(uint32_t senderInstanceId,
143*84e33947SAndroid Build Coastguard Worker const void *eventData) {
144*84e33947SAndroid Build Coastguard Worker const auto data = static_cast<const ChrePigweedNanoappMessage *>(eventData);
145*84e33947SAndroid Build Coastguard Worker pw::span packet(reinterpret_cast<const std::byte *>(data->msg),
146*84e33947SAndroid Build Coastguard Worker data->msgSize);
147*84e33947SAndroid Build Coastguard Worker
148*84e33947SAndroid Build Coastguard Worker pw::Result<uint32_t> result = pw::rpc::ExtractChannelId(packet);
149*84e33947SAndroid Build Coastguard Worker if (!result.status().ok()) {
150*84e33947SAndroid Build Coastguard Worker LOGE("Unable to extract channel ID from packet: %" PRIu8,
151*84e33947SAndroid Build Coastguard Worker static_cast<uint8_t>(result.status().code()));
152*84e33947SAndroid Build Coastguard Worker return false;
153*84e33947SAndroid Build Coastguard Worker }
154*84e33947SAndroid Build Coastguard Worker
155*84e33947SAndroid Build Coastguard Worker if (!validateNanoappChannelId(senderInstanceId, result.value())) {
156*84e33947SAndroid Build Coastguard Worker return false;
157*84e33947SAndroid Build Coastguard Worker }
158*84e33947SAndroid Build Coastguard Worker
159*84e33947SAndroid Build Coastguard Worker chreConfigureNanoappInfoEvents(true);
160*84e33947SAndroid Build Coastguard Worker
161*84e33947SAndroid Build Coastguard Worker mNanoappOutput.setClient(senderInstanceId);
162*84e33947SAndroid Build Coastguard Worker pw::Status status = mServer.OpenChannel(result.value(), mNanoappOutput);
163*84e33947SAndroid Build Coastguard Worker if (status != pw::OkStatus() && status != pw::Status::AlreadyExists()) {
164*84e33947SAndroid Build Coastguard Worker LOGE("Failed to open channel: %" PRIu8, static_cast<uint8_t>(status.code()));
165*84e33947SAndroid Build Coastguard Worker return false;
166*84e33947SAndroid Build Coastguard Worker }
167*84e33947SAndroid Build Coastguard Worker
168*84e33947SAndroid Build Coastguard Worker status = mServer.ProcessPacket(packet);
169*84e33947SAndroid Build Coastguard Worker if (!status.ok()) {
170*84e33947SAndroid Build Coastguard Worker LOGE("Failed to process the packet: %" PRIu8, static_cast<uint8_t>(status.code()));
171*84e33947SAndroid Build Coastguard Worker return false;
172*84e33947SAndroid Build Coastguard Worker }
173*84e33947SAndroid Build Coastguard Worker
174*84e33947SAndroid Build Coastguard Worker return true;
175*84e33947SAndroid Build Coastguard Worker }
176*84e33947SAndroid Build Coastguard Worker
handleHostClientNotification(const void * eventData)177*84e33947SAndroid Build Coastguard Worker void RpcServer::handleHostClientNotification(const void *eventData) {
178*84e33947SAndroid Build Coastguard Worker if (mConnectedHosts.empty()) {
179*84e33947SAndroid Build Coastguard Worker return;
180*84e33947SAndroid Build Coastguard Worker }
181*84e33947SAndroid Build Coastguard Worker
182*84e33947SAndroid Build Coastguard Worker auto notif =
183*84e33947SAndroid Build Coastguard Worker static_cast<const struct chreHostEndpointNotification *>(eventData);
184*84e33947SAndroid Build Coastguard Worker
185*84e33947SAndroid Build Coastguard Worker if (notif->notificationType == HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT) {
186*84e33947SAndroid Build Coastguard Worker size_t hostIndex = mConnectedHosts.find(notif->hostEndpointId);
187*84e33947SAndroid Build Coastguard Worker if (hostIndex != mConnectedHosts.size()) {
188*84e33947SAndroid Build Coastguard Worker mServer
189*84e33947SAndroid Build Coastguard Worker .CloseChannel(kChannelIdHostClient |
190*84e33947SAndroid Build Coastguard Worker static_cast<uint32_t>(notif->hostEndpointId))
191*84e33947SAndroid Build Coastguard Worker .IgnoreError();
192*84e33947SAndroid Build Coastguard Worker mConnectedHosts.erase(hostIndex);
193*84e33947SAndroid Build Coastguard Worker }
194*84e33947SAndroid Build Coastguard Worker }
195*84e33947SAndroid Build Coastguard Worker }
196*84e33947SAndroid Build Coastguard Worker
handleNanoappStopped(const void * eventData)197*84e33947SAndroid Build Coastguard Worker void RpcServer::handleNanoappStopped(const void *eventData) {
198*84e33947SAndroid Build Coastguard Worker auto info = static_cast<const struct chreNanoappInfo *>(eventData);
199*84e33947SAndroid Build Coastguard Worker
200*84e33947SAndroid Build Coastguard Worker if (info->instanceId > kRpcNanoappMaxId) {
201*84e33947SAndroid Build Coastguard Worker LOGE("Invalid nanoapp instance ID %" PRIu32, info->instanceId);
202*84e33947SAndroid Build Coastguard Worker } else if (pw::Status status = mServer.CloseChannel(info->instanceId);
203*84e33947SAndroid Build Coastguard Worker !status.ok()) {
204*84e33947SAndroid Build Coastguard Worker LOGE("Failed to close channel for nanoapp with instance ID %"
205*84e33947SAndroid Build Coastguard Worker PRIu32 ": %" PRIu8, info->instanceId,
206*84e33947SAndroid Build Coastguard Worker static_cast<uint8_t>(status.code()));
207*84e33947SAndroid Build Coastguard Worker }
208*84e33947SAndroid Build Coastguard Worker }
209*84e33947SAndroid Build Coastguard Worker
closeChannel(uint32_t id)210*84e33947SAndroid Build Coastguard Worker pw::Status RpcServer::closeChannel(uint32_t id) {
211*84e33947SAndroid Build Coastguard Worker return mServer.CloseChannel(id);
212*84e33947SAndroid Build Coastguard Worker }
213*84e33947SAndroid Build Coastguard Worker
214*84e33947SAndroid Build Coastguard Worker } // namespace chre
215