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