xref: /aosp_15_r20/system/chre/host/hal_generic/common/context_hub_v4_impl.cc (revision 84e339476a462649f82315436d70fd732297a399)
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