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 
26 #ifndef LOG_TAG
27 #define LOG_TAG "[RpcServer]"
28 #endif  // LOG_TAG
29 
30 namespace chre {
31 
registerServices(size_t numServices,RpcServer::Service * services)32 bool RpcServer::registerServices(size_t numServices,
33                                  RpcServer::Service *services) {
34   // Avoid blowing up the stack with chreServices.
35   constexpr size_t kMaxServices = 8;
36 
37   if (numServices > kMaxServices) {
38     LOGE("Can not register more than %zu services at once", kMaxServices);
39     return false;
40   }
41 
42   chreNanoappRpcService chreServices[kMaxServices];
43 
44   for (size_t i = 0; i < numServices; ++i) {
45     const Service &service = services[i];
46 
47     if (mServer.IsServiceRegistered(service.service)) {
48       return false;
49     }
50 
51     chreServices[i] = {
52         .id = service.id,
53         .version = service.version,
54     };
55 
56     mServer.RegisterService(service.service);
57   }
58 
59   return chrePublishRpcServices(chreServices, numServices);
60 }
61 
setPermissionForNextMessage(uint32_t permission)62 void RpcServer::setPermissionForNextMessage(uint32_t permission) {
63   mPermission.set(permission);
64 }
65 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)66 bool RpcServer::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
67                             const void *eventData) {
68   switch (eventType) {
69     case CHRE_EVENT_MESSAGE_FROM_HOST:
70       return handleMessageFromHost(eventData);
71     case CHRE_EVENT_RPC_REQUEST:
72       return handleMessageFromNanoapp(senderInstanceId, eventData);
73     case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION:
74       handleHostClientNotification(eventData);
75       return true;
76     case CHRE_EVENT_NANOAPP_STOPPED:
77       handleNanoappStopped(eventData);
78       return true;
79     default:
80       return true;
81   }
82 }
83 
close()84 void RpcServer::close() {
85   chreConfigureNanoappInfoEvents(false);
86   // TODO(b/251257328): Disable all notifications at once.
87   while (!mConnectedHosts.empty()) {
88     chreConfigureHostEndpointNotifications(mConnectedHosts[0], false);
89     mConnectedHosts.erase(0);
90   }
91 }
92 
handleMessageFromHost(const void * eventData)93 bool RpcServer::handleMessageFromHost(const void *eventData) {
94   auto *hostMessage = static_cast<const chreMessageFromHostData *>(eventData);
95 
96   if (hostMessage->messageType != CHRE_MESSAGE_TYPE_RPC) {
97     return false;
98   }
99 
100   pw::span packet(static_cast<const std::byte *>(hostMessage->message),
101                   hostMessage->messageSize);
102 
103   pw::Result<uint32_t> result = pw::rpc::ExtractChannelId(packet);
104   if (result.status() != PW_STATUS_OK) {
105     LOGE("Unable to extract channel ID from packet");
106     return false;
107   }
108 
109   if (!validateHostChannelId(hostMessage, result.value())) {
110     return false;
111   }
112 
113   if (!chreConfigureHostEndpointNotifications(hostMessage->hostEndpoint,
114                                               true)) {
115     LOGW("Fail to register for host client updates");
116   }
117 
118   size_t hostIndex = mConnectedHosts.find(hostMessage->hostEndpoint);
119   if (hostIndex == mConnectedHosts.size()) {
120     mConnectedHosts.push_back(hostMessage->hostEndpoint);
121   }
122 
123   mHostOutput.setHostEndpoint(hostMessage->hostEndpoint);
124   mServer.OpenChannel(result.value(), mHostOutput);
125 
126   pw::Status status = mServer.ProcessPacket(packet);
127 
128   if (status != pw::OkStatus()) {
129     LOGE("Failed to process the packet");
130     return false;
131   }
132 
133   return true;
134 }
135 
136 // TODO(b/242301032): factor code with handleMessageFromHost
handleMessageFromNanoapp(uint32_t senderInstanceId,const void * eventData)137 bool RpcServer::handleMessageFromNanoapp(uint32_t senderInstanceId,
138                                          const void *eventData) {
139   const auto data = static_cast<const ChrePigweedNanoappMessage *>(eventData);
140   pw::span packet(reinterpret_cast<const std::byte *>(data->msg),
141                   data->msgSize);
142 
143   pw::Result<uint32_t> result = pw::rpc::ExtractChannelId(packet);
144   if (result.status() != PW_STATUS_OK) {
145     LOGE("Unable to extract channel ID from packet");
146     return false;
147   }
148 
149   if (!validateNanoappChannelId(senderInstanceId, result.value())) {
150     return false;
151   }
152 
153   chreConfigureNanoappInfoEvents(true);
154 
155   mNanoappOutput.setClient(senderInstanceId);
156   mServer.OpenChannel(result.value(), mNanoappOutput);
157 
158   pw::Status success = mServer.ProcessPacket(packet);
159 
160   if (success != pw::OkStatus()) {
161     LOGE("Failed to process the packet");
162     return false;
163   }
164 
165   return true;
166 }
167 
handleHostClientNotification(const void * eventData)168 void RpcServer::handleHostClientNotification(const void *eventData) {
169   if (mConnectedHosts.empty()) {
170     return;
171   }
172 
173   auto notif =
174       static_cast<const struct chreHostEndpointNotification *>(eventData);
175 
176   if (notif->notificationType == HOST_ENDPOINT_NOTIFICATION_TYPE_DISCONNECT) {
177     size_t hostIndex = mConnectedHosts.find(notif->hostEndpointId);
178     if (hostIndex != mConnectedHosts.size()) {
179       mServer.CloseChannel(kChannelIdHostClient |
180                            static_cast<uint32_t>(notif->hostEndpointId));
181       mConnectedHosts.erase(hostIndex);
182     }
183   }
184 }
185 
handleNanoappStopped(const void * eventData)186 void RpcServer::handleNanoappStopped(const void *eventData) {
187   auto info = static_cast<const struct chreNanoappInfo *>(eventData);
188 
189   if (info->instanceId > kRpcNanoappMaxId) {
190     LOGE("Invalid nanoapp Id 0x%08" PRIx32, info->instanceId);
191   } else {
192     mServer.CloseChannel(info->instanceId);
193   }
194 }
195 
closeChannel(uint32_t id)196 pw::Status RpcServer::closeChannel(uint32_t id) {
197   return mServer.CloseChannel(id);
198 }
199 
200 }  // namespace chre