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