• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
~RpcServer()32 RpcServer::~RpcServer() {
33   chreConfigureNanoappInfoEvents(false);
34   // TODO(b/251257328): Disable all notifications at once.
35   while (!mConnectedHosts.empty()) {
36     chreConfigureHostEndpointNotifications(mConnectedHosts[0], false);
37     mConnectedHosts.erase(0);
38   }
39 }
40 
registerServices(size_t numServices,RpcServer::Service * services)41 bool RpcServer::registerServices(size_t numServices,
42                                  RpcServer::Service *services) {
43   // Avoid blowing up the stack with chreServices.
44   constexpr size_t kMaxServices = 8;
45 
46   if (numServices > kMaxServices) {
47     LOGE("Can not register more than %zu services at once", kMaxServices);
48     return false;
49   }
50 
51   chreNanoappRpcService chreServices[kMaxServices];
52 
53   for (size_t i = 0; i < numServices; ++i) {
54     const Service &service = services[i];
55 
56     if (mServer.IsServiceRegistered(service.service)) {
57       return false;
58     }
59 
60     chreServices[i] = {
61         .id = service.id,
62         .version = service.version,
63     };
64 
65     mServer.RegisterService(service.service);
66   }
67 
68   return chrePublishRpcServices(chreServices, numServices);
69 }
70 
setPermissionForNextMessage(uint32_t permission)71 void RpcServer::setPermissionForNextMessage(uint32_t permission) {
72   mPermission.set(permission);
73 }
74 
handleEvent(uint32_t senderInstanceId,uint16_t eventType,const void * eventData)75 bool RpcServer::handleEvent(uint32_t senderInstanceId, uint16_t eventType,
76                             const void *eventData) {
77   switch (eventType) {
78     case CHRE_EVENT_MESSAGE_FROM_HOST:
79       return handleMessageFromHost(eventData);
80     case ChreChannelOutputBase::PW_RPC_CHRE_NAPP_REQUEST_EVENT_TYPE:
81       return handleMessageFromNanoapp(senderInstanceId, eventData);
82     case CHRE_EVENT_HOST_ENDPOINT_NOTIFICATION:
83       handleHostClientNotification(eventData);
84       return true;
85     case CHRE_EVENT_NANOAPP_STOPPED:
86       handleNanoappStopped(eventData);
87       return true;
88     default:
89       return true;
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 !=
97       ChreChannelOutputBase::PW_RPC_CHRE_HOST_MESSAGE_TYPE) {
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() != PW_STATUS_OK) {
106     LOGE("Unable to extract channel ID from packet");
107     return false;
108   }
109 
110   if (!validateHostChannelId(hostMessage, result.value())) {
111     return false;
112   }
113 
114   if (!chreConfigureHostEndpointNotifications(hostMessage->hostEndpoint,
115                                               true)) {
116     LOGW("Fail to register for host client updates");
117   }
118 
119   size_t hostIndex = mConnectedHosts.find(hostMessage->hostEndpoint);
120   if (hostIndex == mConnectedHosts.size()) {
121     mConnectedHosts.push_back(hostMessage->hostEndpoint);
122   }
123 
124   mHostOutput.setHostEndpoint(hostMessage->hostEndpoint);
125   mServer.OpenChannel(result.value(), mHostOutput);
126 
127   pw::Status status = mServer.ProcessPacket(packet);
128 
129   if (status != pw::OkStatus()) {
130     LOGE("Failed to process the packet");
131     return false;
132   }
133 
134   return true;
135 }
136 
137 // TODO(b/242301032): factor code with handleMessageFromHost
handleMessageFromNanoapp(uint32_t senderInstanceId,const void * eventData)138 bool RpcServer::handleMessageFromNanoapp(uint32_t senderInstanceId,
139                                          const void *eventData) {
140   const auto data = static_cast<const ChrePigweedNanoappMessage *>(eventData);
141   pw::span packet(static_cast<const std::byte *>(data->msg), 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