1 /*
2 * Copyright (C) 2024 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 "context_hub_v4_impl.h"
18
19 #include <assert.h>
20 #include <inttypes.h>
21
22 #include <functional>
23 #include <optional>
24 #include <string>
25 #include <vector>
26
27 #include <aidl/android/hardware/contexthub/BnContextHub.h>
28 #include <chre_host/generated/host_messages_generated.h>
29 #include <chre_host/log.h>
30
31 namespace android::hardware::contexthub::common::implementation {
32
33 using ::aidl::android::hardware::contexthub::BnContextHub;
34 using ::chre::fbs::ChreMessage;
35 using HostHub = MessageHubManager::HostHub;
36
init()37 void ContextHubV4Impl::init() {
38 // TODO(b/378545373): Send message to get hubs/endpoints state dump to
39 // initialize mManager.
40 }
41
42 namespace {
43
fromPwStatus(pw::Status status)44 ScopedAStatus fromPwStatus(pw::Status status) {
45 switch (status.code()) {
46 case PW_STATUS_OK:
47 return ScopedAStatus::ok();
48 case PW_STATUS_NOT_FOUND:
49 [[fallthrough]];
50 case PW_STATUS_ALREADY_EXISTS:
51 [[fallthrough]];
52 case PW_STATUS_OUT_OF_RANGE:
53 [[fallthrough]];
54 case PW_STATUS_PERMISSION_DENIED:
55 [[fallthrough]];
56 case PW_STATUS_INVALID_ARGUMENT:
57 return ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
58 case PW_STATUS_UNIMPLEMENTED:
59 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
60 default:
61 return ScopedAStatus::fromServiceSpecificError(
62 BnContextHub::EX_CONTEXT_HUB_UNSPECIFIED);
63 }
64 }
65
66 } // namespace
67
getHubs(std::vector<HubInfo> * hubs)68 ScopedAStatus ContextHubV4Impl::getHubs(std::vector<HubInfo> *hubs) {
69 *hubs = mManager.getEmbeddedHubs();
70 return ScopedAStatus::ok();
71 }
72
getEndpoints(std::vector<EndpointInfo> * endpoints)73 ScopedAStatus ContextHubV4Impl::getEndpoints(
74 std::vector<EndpointInfo> *endpoints) {
75 *endpoints = mManager.getEmbeddedEndpoints();
76 return ScopedAStatus::ok();
77 }
78
registerEndpoint(const EndpointInfo & endpoint)79 ScopedAStatus ContextHubV4Impl::registerEndpoint(const EndpointInfo &endpoint) {
80 std::shared_ptr<HostHub> hub =
81 mManager.getHostHubByPid(AIBinder_getCallingPid());
82 assert(hub != nullptr);
83 if (auto status = hub->addEndpoint(hub, endpoint); !status.ok()) {
84 LOGE("Failed to register endpoint %" PRId64 " on hub %" PRId64
85 " with %" PRId32,
86 endpoint.id.id, hub->id(), status.code());
87 return fromPwStatus(status);
88 }
89 // TODO(b/378545373): Send the endpoint info to CHRE.
90 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
91 }
92
unregisterEndpoint(const EndpointInfo & endpoint)93 ScopedAStatus ContextHubV4Impl::unregisterEndpoint(
94 const EndpointInfo &endpoint) {
95 std::shared_ptr<HostHub> hub =
96 mManager.getHostHubByPid(AIBinder_getCallingPid());
97 assert(hub != nullptr);
98 if (auto status = hub->removeEndpoint(endpoint.id); !status.ok()) {
99 LOGE("Failed to unregister endpoint %" PRId32 " on hub %" PRId32
100 " with %" PRId32,
101 endpoint.id.id, hub->id(), status.code());
102 return fromPwStatus(status);
103 }
104 // TODO(b/378545373): Send the endpoint info to CHRE.
105 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
106 }
107
registerEndpointCallback(const std::shared_ptr<IEndpointCallback> & callback)108 ScopedAStatus ContextHubV4Impl::registerEndpointCallback(
109 const std::shared_ptr<IEndpointCallback> &callback) {
110 std::shared_ptr<HostHub> hub =
111 mManager.getHostHubByPid(AIBinder_getCallingPid());
112 assert(hub != nullptr);
113 return fromPwStatus(hub->setCallback(callback));
114 }
115
requestSessionIdRange(int32_t size,std::vector<int32_t> * ids)116 ScopedAStatus ContextHubV4Impl::requestSessionIdRange(
117 int32_t size, std::vector<int32_t> *ids) {
118 std::shared_ptr<HostHub> hub =
119 mManager.getHostHubByPid(AIBinder_getCallingPid());
120 assert(hub != nullptr);
121 auto statusOrRange = hub->reserveSessionIdRange(size);
122 if (!statusOrRange.ok()) {
123 LOGE("Failed to reserve %" PRId32 " session ids on hub %" PRId64
124 " with %" PRId32,
125 size, hub->id(), statusOrRange.status().code());
126 return fromPwStatus(statusOrRange.status());
127 }
128 ids->resize(2);
129 (*ids)[0] = statusOrRange->first;
130 (*ids)[1] = statusOrRange->second;
131 return ScopedAStatus::ok();
132 }
133
openEndpointSession(int32_t sessionId,const EndpointId & destination,const EndpointId & initiator,const std::optional<std::string> &)134 ScopedAStatus ContextHubV4Impl::openEndpointSession(
135 int32_t sessionId, const EndpointId &destination,
136 const EndpointId &initiator,
137 const std::optional<std::string> & /*serviceDescriptor*/) {
138 std::shared_ptr<HostHub> hub =
139 mManager.getHostHubByPid(AIBinder_getCallingPid());
140 assert(hub != nullptr);
141 pw::Result<std::shared_ptr<HostHub>> statusOrPruneHub =
142 hub->openSession(hub, initiator, destination, sessionId);
143 if (!statusOrPruneHub.ok()) {
144 LOGE("Failed to open session %" PRId32 " from (%" PRId64 ", %" PRId64
145 ") to (%" PRId64 ", %" PRId64 ") with %" PRId32,
146 sessionId, initiator.hubId, initiator.id, destination.hubId,
147 destination.id, statusOrPruneHub.status().code());
148 return fromPwStatus(statusOrPruneHub.status());
149 } else if (*statusOrPruneHub) {
150 // Send a closed session notification on the hub that hosted the pruned
151 // session.
152 auto status = (*statusOrPruneHub)->closeSession(sessionId);
153 LOGD("Pruning session %" PRIu16 " with status %" PRId32, sessionId,
154 status.code());
155 }
156 // TODO(b/378545373): Send the session open request to CHRE.
157 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
158 }
159
sendMessageToEndpoint(int32_t sessionId,const Message &)160 ScopedAStatus ContextHubV4Impl::sendMessageToEndpoint(int32_t sessionId,
161 const Message & /*msg*/) {
162 std::shared_ptr<HostHub> hub =
163 mManager.getHostHubByPid(AIBinder_getCallingPid());
164 assert(hub != nullptr);
165 if (auto status = hub->checkSessionOpen(sessionId); !status.ok()) {
166 if (status.IsUnavailable()) {
167 hub->getCallback()->onCloseEndpointSession(sessionId,
168 Reason::ENDPOINT_GONE);
169 } else {
170 LOGE("Failed to verify session %" PRId32 " on hub %" PRId64
171 " with %" PRId32,
172 sessionId, hub->id(), status.code());
173 }
174 return fromPwStatus(status);
175 }
176 // TODO(b/378545373): Handle reliable messages.
177 // TODO(b/378545373): Send the message to CHRE.
178 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
179 }
180
sendMessageDeliveryStatusToEndpoint(int32_t sessionId,const MessageDeliveryStatus &)181 ScopedAStatus ContextHubV4Impl::sendMessageDeliveryStatusToEndpoint(
182 int32_t sessionId, const MessageDeliveryStatus & /*msgStatus*/) {
183 std::shared_ptr<HostHub> hub =
184 mManager.getHostHubByPid(AIBinder_getCallingPid());
185 assert(hub != nullptr);
186 if (auto status = hub->checkSessionOpen(sessionId); !status.ok()) {
187 if (status.IsUnavailable()) {
188 hub->getCallback()->onCloseEndpointSession(sessionId,
189 Reason::ENDPOINT_GONE);
190 } else {
191 LOGE("Failed to verify session %" PRId32 " on hub %" PRId64
192 " with %" PRId32,
193 sessionId, hub->id(), status.code());
194 }
195 return fromPwStatus(status);
196 }
197 // TODO(b/378545373): Send the message to CHRE.
198 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
199 }
200
closeEndpointSession(int32_t sessionId,Reason)201 ScopedAStatus ContextHubV4Impl::closeEndpointSession(int32_t sessionId,
202 Reason /*reason*/) {
203 std::shared_ptr<HostHub> hub =
204 mManager.getHostHubByPid(AIBinder_getCallingPid());
205 assert(hub != nullptr);
206 if (auto status = hub->closeSession(sessionId); !status.ok()) {
207 LOGE("Failed to close session %" PRId32 " on hub %" PRId64 " with %" PRId32,
208 sessionId, hub->id(), status.code());
209 return fromPwStatus(status);
210 }
211 hub->getCallback()->onCloseEndpointSession(
212 sessionId, Reason::CLOSE_ENDPOINT_SESSION_REQUESTED);
213 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
214 }
215
endpointSessionOpenComplete(int32_t sessionId)216 ScopedAStatus ContextHubV4Impl::endpointSessionOpenComplete(int32_t sessionId) {
217 std::shared_ptr<HostHub> hub =
218 mManager.getHostHubByPid(AIBinder_getCallingPid());
219 assert(hub != nullptr);
220 if (auto status = hub->ackSession(sessionId); !status.ok()) {
221 if (status.IsUnavailable()) {
222 hub->getCallback()->onCloseEndpointSession(sessionId,
223 Reason::ENDPOINT_GONE);
224 } else {
225 LOGE("Failed to verify session %" PRId32 " on hub %" PRId64
226 " with %" PRId32,
227 sessionId, hub->id(), status.code());
228 }
229 return fromPwStatus(status);
230 }
231 // TODO(b/378545373): Send the session id to CHRE.
232 return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
233 }
234
handleMessageFromChre(const::chre::fbs::ChreMessageUnion & message)235 bool ContextHubV4Impl::handleMessageFromChre(
236 const ::chre::fbs::ChreMessageUnion &message) {
237 switch (message.type) {
238 case ChreMessage::GetMessageHubsAndEndpointsResponse:
239 onGetMessageHubsAndEndpointsResponse(
240 *message.AsGetMessageHubsAndEndpointsResponse());
241 break;
242 case ChreMessage::RegisterMessageHub:
243 onRegisterMessageHub(*message.AsRegisterMessageHub());
244 break;
245 case ChreMessage::UnregisterMessageHub:
246 onUnregisterMessageHub(*message.AsUnregisterMessageHub());
247 break;
248 case ChreMessage::RegisterEndpoint:
249 onRegisterEndpoint(*message.AsRegisterEndpoint());
250 break;
251 case ChreMessage::OpenEndpointSessionRequest:
252 onOpenEndpointSessionRequest(*message.AsOpenEndpointSessionRequest());
253 break;
254 case ChreMessage::EndpointSessionOpened:
255 onEndpointSessionOpened(*message.AsEndpointSessionOpened());
256 break;
257 case ChreMessage::EndpointSessionClosed:
258 onEndpointSessionClosed(*message.AsEndpointSessionClosed());
259 break;
260 case ChreMessage::EndpointSessionMessage:
261 onEndpointSessionMessage(*message.AsEndpointSessionMessage());
262 break;
263 case ChreMessage::EndpointSessionMessageDeliveryStatus:
264 onEndpointSessionMessageDeliveryStatus(
265 *message.AsEndpointSessionMessageDeliveryStatus());
266 break;
267 default:
268 LOGW("Got unexpected message type %" PRIu8,
269 static_cast<uint8_t>(message.type));
270 return false;
271 }
272 return true;
273 }
274
onGetMessageHubsAndEndpointsResponse(const::chre::fbs::GetMessageHubsAndEndpointsResponseT &)275 void ContextHubV4Impl::onGetMessageHubsAndEndpointsResponse(
276 const ::chre::fbs::GetMessageHubsAndEndpointsResponseT & /*msg*/) {
277 // TODO(b/378545373): Parse flatbuffer message
278 std::vector<HubInfo> hubs;
279 std::vector<EndpointInfo> endpoints;
280 LOGI("Initializing embedded message hub cache");
281 mManager.initEmbeddedHubsAndEndpoints(hubs, endpoints);
282 }
283
onRegisterMessageHub(const::chre::fbs::RegisterMessageHubT &)284 void ContextHubV4Impl::onRegisterMessageHub(
285 const ::chre::fbs::RegisterMessageHubT & /*msg*/) {
286 // TODO(b/378545373): Parse flatbuffer message
287 HubInfo hub;
288 LOGI("Embedded message hub %" PRId64 " registered", hub.hubId);
289 mManager.addEmbeddedHub(hub);
290 }
291
onUnregisterMessageHub(const::chre::fbs::UnregisterMessageHubT &)292 void ContextHubV4Impl::onUnregisterMessageHub(
293 const ::chre::fbs::UnregisterMessageHubT & /*msg*/) {
294 // TODO(b/378545373): Parse flatbuffer message
295 int64_t id = 0;
296 LOGI("Embedded message hub %" PRId64 " unregistered", id);
297 std::vector<EndpointId> endpoints = mManager.removeEmbeddedHub(id);
298 if (!endpoints.empty()) {
299 mManager.forEachHostHub([&endpoints](HostHub &hub) {
300 hub.getCallback()->onEndpointStopped(endpoints, Reason::HUB_RESET);
301 });
302 }
303 }
304
onRegisterEndpoint(const::chre::fbs::RegisterEndpointT &)305 void ContextHubV4Impl::onRegisterEndpoint(
306 const ::chre::fbs::RegisterEndpointT & /*msg*/) {
307 // TODO(b/378545373): Parse flatbuffer message
308 EndpointInfo endpoint;
309 LOGI("Adding embedded endpoint (%" PRId64 ", %" PRId64 ")", endpoint.id.hubId,
310 endpoint.id.id);
311 mManager.addEmbeddedEndpoint(endpoint);
312 mManager.forEachHostHub([&endpoint](HostHub &hub) {
313 hub.getCallback()->onEndpointStarted({endpoint});
314 });
315 }
316
onUnregisterEndpoint(const::chre::fbs::UnregisterEndpointT &)317 void ContextHubV4Impl::onUnregisterEndpoint(
318 const ::chre::fbs::UnregisterEndpointT & /*msg*/) {
319 // TODO(b/378545373): Parse flatbuffer message
320 EndpointId endpoint;
321 LOGI("Removing embedded endpoint (%" PRId64 ", %" PRId64 ")", endpoint.hubId,
322 endpoint.id);
323 mManager.removeEmbeddedEndpoint(endpoint);
324 mManager.forEachHostHub([&endpoint](HostHub &hub) {
325 hub.getCallback()->onEndpointStopped({endpoint}, Reason::ENDPOINT_GONE);
326 });
327 }
328
onOpenEndpointSessionRequest(const::chre::fbs::OpenEndpointSessionRequestT &)329 void ContextHubV4Impl::onOpenEndpointSessionRequest(
330 const ::chre::fbs::OpenEndpointSessionRequestT & /*msg*/) {
331 // TODO(b/378545373): Parse flatbuffer message
332 std::optional<std::string> serviceDescriptor;
333 EndpointId local, remote;
334 uint16_t sessionId = 0;
335 LOGD("New session (%" PRIu16 ") request from (%" PRId64 ", %" PRId64
336 ") to "
337 "(%" PRId64 ", %" PRId64 ")",
338 sessionId, remote.hubId, remote.id, local.hubId, local.id);
339
340 // Look up the host hub based on the host endpoint.
341 std::shared_ptr<HostHub> hub = mManager.getHostHubByEndpointId(local);
342 if (!hub) {
343 LOGW("Unable to find host hub");
344 return;
345 }
346
347 // Record the open session request and pass it on to the appropriate client.
348 auto statusOrPruneHub = hub->openSession(hub, local, remote, sessionId);
349 if (!statusOrPruneHub.ok()) {
350 LOGE("Failed to request session %" PRIu16 " with %" PRId32, sessionId,
351 statusOrPruneHub.status().code());
352 return;
353 } else if (*statusOrPruneHub) {
354 // Send a closed session notification on the hub that hosted the pruned
355 // session.
356 auto status = (*statusOrPruneHub)->closeSession(sessionId);
357 LOGD("Pruning session %" PRIu16 " with status %" PRId32, sessionId,
358 status.code());
359 }
360 hub->getCallback()->onEndpointSessionOpenRequest(
361 sessionId, local, remote, std::move(serviceDescriptor));
362 }
363
364 namespace {
365
logGetHubFailure(pw::Status status,int32_t sessionId)366 void logGetHubFailure(pw::Status status, int32_t sessionId) {
367 if (status.IsUnavailable()) {
368 LOGD("Session %" PRId32 " was pruned.", sessionId);
369 } else {
370 LOGE("Failed to operate on session %" PRId32 " with %" PRId32, sessionId,
371 status.code());
372 }
373 }
374
375 } // namespace
376
onEndpointSessionOpened(const::chre::fbs::EndpointSessionOpenedT &)377 void ContextHubV4Impl::onEndpointSessionOpened(
378 const ::chre::fbs::EndpointSessionOpenedT & /*msg*/) {
379 // TODO(b/378545373): Parse flatbuffer message
380 int32_t id = 0;
381 LOGD("New session ack for id %" PRId32, id);
382 auto statusOrHub = mManager.ackSessionAndGetHostHub(id);
383 if (!statusOrHub.ok()) {
384 logGetHubFailure(statusOrHub.status(), id);
385 // TODO(b/378545373): Send a notification back to CHRE.
386 return;
387 }
388
389 // Only send a session open complete message to the host hub client if it was
390 // the initiator.
391 if (static_cast<uint16_t>(id) >= MessageHubManager::kHostSessionIdBase)
392 (*statusOrHub)->getCallback()->onEndpointSessionOpenComplete(id);
393 }
394
onEndpointSessionClosed(const::chre::fbs::EndpointSessionClosedT &)395 void ContextHubV4Impl::onEndpointSessionClosed(
396 const ::chre::fbs::EndpointSessionClosedT & /*msg*/) {
397 // TODO(b/378545373): Parse flatbuffer message
398 int32_t id = 0;
399 Reason reason = Reason::UNSPECIFIED;
400 LOGD("Closing session id %" PRId32 " for %" PRIu8, id, reason);
401 auto statusOrHub = mManager.checkSessionOpenAndGetHostHub(id);
402 if (!statusOrHub.ok()) {
403 logGetHubFailure(statusOrHub.status(), id);
404 return;
405 }
406 (*statusOrHub)->getCallback()->onCloseEndpointSession(id, reason);
407 }
408
onEndpointSessionMessage(const::chre::fbs::EndpointSessionMessageT &)409 void ContextHubV4Impl::onEndpointSessionMessage(
410 const ::chre::fbs::EndpointSessionMessageT & /*msg*/) {
411 // TODO(b/378545373): Parse flatbuffer message
412 Message message;
413 int32_t sessionId = 0;
414 auto statusOrHub = mManager.checkSessionOpenAndGetHostHub(sessionId);
415 if (!statusOrHub.ok()) {
416 logGetHubFailure(statusOrHub.status(), sessionId);
417 // TODO(b/378545373): Send a notification back to CHRE.
418 return;
419 }
420 (*statusOrHub)->getCallback()->onMessageReceived(sessionId, message);
421 }
422
onEndpointSessionMessageDeliveryStatus(const::chre::fbs::EndpointSessionMessageDeliveryStatusT &)423 void ContextHubV4Impl::onEndpointSessionMessageDeliveryStatus(
424 const ::chre::fbs::EndpointSessionMessageDeliveryStatusT & /*msg*/) {
425 // TODO(b/378545373): Parse flatbuffer message
426 MessageDeliveryStatus status;
427 int32_t sessionId = 0;
428 auto statusOrHub = mManager.checkSessionOpenAndGetHostHub(sessionId);
429 if (!statusOrHub.ok()) {
430 logGetHubFailure(statusOrHub.status(), sessionId);
431 // TODO(b/378545373): Send a notification back to CHRE.
432 return;
433 }
434 // TODO(b/378545373): Handle reliable messages.
435 (*statusOrHub)
436 ->getCallback()
437 ->onMessageDeliveryStatusReceived(sessionId, status);
438 }
439
onHostHubDown(int64_t)440 void ContextHubV4Impl::onHostHubDown(int64_t /*id*/) {
441 // TODO(b/378545373): Send an UnregisterMessageHub message to CHRE with id.
442 }
443
444 } // namespace android::hardware::contexthub::common::implementation
445