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