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