1 /*
2 * Copyright (C) 2025 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/core/host_message_hub_manager.h"
18 #include "chre/target_platform/log.h"
19
20 #ifdef CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
21
22 #include <cstring>
23 #include <optional>
24
25 #include "chre/core/event_loop_manager.h"
26 #include "chre/platform/assert.h"
27 #include "chre/platform/log.h"
28 #include "chre/platform/memory.h"
29 #include "chre/platform/mutex.h"
30 #include "chre/platform/shared/fbs/host_messages_generated.h"
31 #include "chre/platform/shared/host_protocol_chre.h"
32 #include "chre/util/lock_guard.h"
33 #include "chre/util/memory.h"
34 #include "chre/util/system/message_common.h"
35 #include "chre/util/system/message_router.h"
36
37 #include "pw_allocator/unique_ptr.h"
38 #include "pw_function/function.h"
39 #include "pw_intrusive_ptr/intrusive_ptr.h"
40 #include "pw_span/span.h"
41
42 namespace chre {
43
44 using ::chre::message::EndpointId;
45 using ::chre::message::EndpointInfo;
46 using ::chre::message::MESSAGE_HUB_ID_INVALID;
47 using ::chre::message::MessageHubId;
48 using ::chre::message::MessageHubInfo;
49 using ::chre::message::MessageRouter;
50 using ::chre::message::MessageRouterSingleton;
51 using ::chre::message::Reason;
52 using ::chre::message::ServiceInfo;
53 using ::chre::message::Session;
54 using ::chre::message::SessionId;
55
~HostMessageHubManager()56 HostMessageHubManager::~HostMessageHubManager() {
57 LockGuard<Mutex> hostLock(mHubsLock);
58 clearHubsLocked();
59 }
60
onHostTransportReady(HostCallback & cb)61 void HostMessageHubManager::onHostTransportReady(HostCallback &cb) {
62 CHRE_ASSERT_LOG(mCb == nullptr,
63 "HostMessageHubManager::init() called more than once");
64 mCb = &cb;
65 }
66
reset()67 void HostMessageHubManager::reset() {
68 LOGI("Resetting HostMessageHubManager");
69 CHRE_ASSERT_NOT_NULL(mCb);
70 LockGuard<Mutex> hostLock(mHubsLock);
71 clearHubsLocked();
72
73 // Serialize the following against any other embedded hub or endpoint
74 // registration events.
75 LockGuard<Mutex> embeddedLock(mEmbeddedHubOpLock);
76
77 // Notify the HAL to accept embedded hub/endpoint registrations.
78 mCb->onReset();
79 MessageRouterSingleton::get()->forEachMessageHub(
80 [this](const MessageHubInfo &info) {
81 mCb->onHubRegistered(info);
82 return false;
83 });
84 MessageRouterSingleton::get()->forEachEndpoint(
85 [this](const MessageHubInfo &hub, const EndpointInfo &endpoint) {
86 mCb->onEndpointRegistered(hub.id, endpoint);
87 });
88 MessageRouterSingleton::get()->forEachService(
89 [this](const MessageHubInfo &hub, const EndpointInfo &endpoint,
90 const ServiceInfo &service) {
91 mCb->onEndpointService(hub.id, endpoint.id, service);
92 return false;
93 });
94 MessageRouterSingleton::get()->forEachEndpoint(
95 [this](const MessageHubInfo &hub, const EndpointInfo &endpoint) {
96 mCb->onEndpointReady(hub.id, endpoint.id);
97 });
98 LOGI("Initialized HostMessageHubManager");
99 }
100
registerHub(const MessageHubInfo & info)101 void HostMessageHubManager::registerHub(const MessageHubInfo &info) {
102 LockGuard<Mutex> lock(mHubsLock);
103 pw::IntrusiveList<Endpoint> endpoints;
104 HostMessageHubManager::Hub::createLocked(this, info, endpoints);
105 }
106
unregisterHub(MessageHubId id)107 void HostMessageHubManager::unregisterHub(MessageHubId id) {
108 LockGuard<Mutex> lock(mHubsLock);
109
110 for (auto it = mHubs.begin(); it != mHubs.end(); ++it) {
111 if ((*it)->getMessageHub().getId() == id) {
112 (*it)->clear();
113 mHubs.erase(it);
114 return;
115 }
116 }
117 LOGE("No host hub 0x%" PRIx64 " for unregister", id);
118 }
119
registerEndpoint(MessageHubId hubId,const EndpointInfo & info,DynamicVector<ServiceInfo> && services)120 void HostMessageHubManager::registerEndpoint(
121 MessageHubId hubId, const EndpointInfo &info,
122 DynamicVector<ServiceInfo> &&services) {
123 LockGuard<Mutex> lock(mHubsLock);
124 for (auto &hub : mHubs) {
125 if (hub->getMessageHub().getId() != hubId) continue;
126 hub->addEndpoint(info, std::move(services));
127 return;
128 }
129 LOGE("No host hub 0x%" PRIx64 " for add endpoint", hubId);
130 }
131
unregisterEndpoint(MessageHubId hubId,EndpointId id)132 void HostMessageHubManager::unregisterEndpoint(MessageHubId hubId,
133 EndpointId id) {
134 LockGuard<Mutex> lock(mHubsLock);
135 for (auto &hub : mHubs) {
136 if (hub->getMessageHub().getId() != hubId) continue;
137 hub->removeEndpoint(id);
138 hub->getMessageHub().unregisterEndpoint(id);
139 return;
140 }
141 LOGE("No host hub 0x%" PRIx64 " for unregister endpoint", hubId);
142 }
143
openSession(MessageHubId hubId,EndpointId endpointId,MessageHubId destinationHubId,EndpointId destinationEndpointId,SessionId sessionId,const char * serviceDescriptor)144 void HostMessageHubManager::openSession(MessageHubId hubId,
145 EndpointId endpointId,
146 MessageHubId destinationHubId,
147 EndpointId destinationEndpointId,
148 SessionId sessionId,
149 const char *serviceDescriptor) {
150 LockGuard<Mutex> lock(mHubsLock);
151 for (auto &hub : mHubs) {
152 if (hub->getMessageHub().getId() != hubId) continue;
153 if (hub->getMessageHub().openSession(
154 endpointId, destinationHubId, destinationEndpointId,
155 serviceDescriptor, sessionId) != sessionId) {
156 mCb->onSessionClosed(hubId, sessionId,
157 Reason::OPEN_ENDPOINT_SESSION_REQUEST_REJECTED);
158 }
159 return;
160 }
161 LOGE("No host hub 0x%" PRIx64 " for open session", hubId);
162 }
163
ackSession(MessageHubId hubId,SessionId sessionId)164 void HostMessageHubManager::ackSession(MessageHubId hubId,
165 SessionId sessionId) {
166 LockGuard<Mutex> lock(mHubsLock);
167 for (auto &hub : mHubs) {
168 if (hub->getMessageHub().getId() != hubId) continue;
169 hub->getMessageHub().onSessionOpenComplete(sessionId);
170 mCb->onSessionOpened(hubId, sessionId);
171 return;
172 }
173 LOGE("No host hub 0x%" PRIx64 " for ack session", hubId);
174 }
175
closeSession(MessageHubId hubId,SessionId sessionId,Reason reason)176 void HostMessageHubManager::closeSession(MessageHubId hubId,
177 SessionId sessionId, Reason reason) {
178 LockGuard<Mutex> lock(mHubsLock);
179 for (auto &hub : mHubs) {
180 if (hub->getMessageHub().getId() != hubId) continue;
181 hub->getMessageHub().closeSession(sessionId, reason);
182 return;
183 }
184 LOGE("No host hub 0x%" PRIx64 " for close session", hubId);
185 }
186
sendMessage(MessageHubId hubId,SessionId sessionId,pw::span<const std::byte> data,uint32_t type,uint32_t permissions)187 void HostMessageHubManager::sendMessage(MessageHubId hubId, SessionId sessionId,
188 pw::span<const std::byte> data,
189 uint32_t type, uint32_t permissions) {
190 LockGuard<Mutex> lock(mHubsLock);
191 for (auto &hub : mHubs) {
192 if (hub->getMessageHub().getId() != hubId) continue;
193 auto dataCopy = mMsgAllocator.MakeUniqueArray<std::byte>(data.size());
194 if (dataCopy == nullptr) {
195 LOGE("Failed to allocate endpoint message from host hub 0x%" PRIx64
196 " over session %" PRIu16,
197 hubId, sessionId);
198 return;
199 }
200 std::memcpy(dataCopy.get(), data.data(), data.size());
201
202 // Note: We are assuming here that no host hubs will create sessions with
203 // themselves as it is not allowed by the HAL API.
204 hub->getMessageHub().sendMessage(std::move(dataCopy), type, permissions,
205 sessionId);
206 return;
207 }
208 LOGE("No host hub 0x%" PRIx64 " for send message", hubId);
209 }
210
createLocked(HostMessageHubManager * manager,const MessageHubInfo & info,pw::IntrusiveList<Endpoint> & endpoints)211 bool HostMessageHubManager::Hub::createLocked(
212 HostMessageHubManager *manager, const MessageHubInfo &info,
213 pw::IntrusiveList<Endpoint> &endpoints) {
214 CHRE_ASSERT(manager != nullptr);
215
216 // If there is an available slot, create a new Hub and try to register it with
217 // MessageRouter, cleaning it up on failure.
218 if (manager->mHubs.full()) {
219 LOGE("No space to register new host hub 0x%" PRIx64, info.id);
220 deallocateEndpoints(endpoints);
221 return false;
222 }
223
224 Hub *hubPtr = memoryAlloc<Hub>(manager, info.name, endpoints);
225 if (hubPtr == nullptr) {
226 LOGE("Failed to allocate storage for new host hub %" PRIu64, info.id);
227 deallocateEndpoints(endpoints);
228 return false;
229 }
230
231 pw::IntrusivePtr<Hub> hub(hubPtr);
232 manager->mHubs.push_back(hub);
233 std::optional<MessageRouter::MessageHub> maybeHub =
234 MessageRouterSingleton::get()->registerMessageHub(hub->kName, info.id,
235 hub);
236 if (!maybeHub) {
237 LOGE("Failed to register host hub 0x%" PRIx64, info.id);
238 manager->mHubs.pop_back();
239 return false;
240 }
241 hub->mMessageHub = std::move(*maybeHub);
242 return true;
243 }
244
Hub(HostMessageHubManager * manager,const char * name,pw::IntrusiveList<Endpoint> & endpoints)245 HostMessageHubManager::Hub::Hub(HostMessageHubManager *manager,
246 const char *name,
247 pw::IntrusiveList<Endpoint> &endpoints)
248 : mManager(manager) {
249 std::strncpy(kName, name, kNameMaxLen);
250 kName[kNameMaxLen] = 0;
251 mEndpoints.splice_after(mEndpoints.before_begin(), endpoints);
252 }
253
~Hub()254 HostMessageHubManager::Hub::~Hub() {
255 // clear() should be explicitly called before destruction.
256 CHRE_ASSERT_LOG(!mMessageHub.isRegistered(),
257 "Hub destroyed while registered");
258 }
259
clear()260 void HostMessageHubManager::Hub::clear() {
261 getMessageHub().unregister();
262
263 // This lock needs to be held to ensure the manager does not destruct
264 // while deallocating endpoints are called.
265 LockGuard<Mutex> managerLock(mManagerLock);
266 mManager = nullptr;
267
268 LockGuard<Mutex> lock(mEndpointsLock);
269 deallocateEndpoints(mEndpoints);
270 }
271
addEndpoint(const EndpointInfo & info,DynamicVector<ServiceInfo> && services)272 void HostMessageHubManager::Hub::addEndpoint(
273 const EndpointInfo &info, DynamicVector<ServiceInfo> &&services) {
274 Endpoint *endpoint = nullptr;
275 {
276 LockGuard<Mutex> managerLock(mManagerLock);
277 CHRE_ASSERT_LOG(mManager != nullptr,
278 "The HostMessageHubManager has been destroyed.");
279
280 endpoint = mManager->mEndpointAllocator.allocate(info, std::move(services));
281 if (endpoint == nullptr) {
282 LOGE("Failed to allocate storage for endpoint (0x%" PRIx64 ", 0x%" PRIx64
283 ")",
284 mMessageHub.getId(), info.id);
285 for (const auto &service : services)
286 memoryFree(const_cast<char *>(service.serviceDescriptor));
287 return;
288 }
289 }
290
291 {
292 LockGuard<Mutex> lock(mEndpointsLock);
293 mEndpoints.push_back(*endpoint);
294 }
295 mMessageHub.registerEndpoint(info.id);
296 }
297
removeEndpoint(EndpointId id)298 void HostMessageHubManager::Hub::removeEndpoint(EndpointId id) {
299 Endpoint *endpoint = nullptr;
300 {
301 LockGuard<Mutex> lock(mEndpointsLock);
302 for (auto it = mEndpoints.begin(), eraseIt = mEndpoints.before_begin();
303 it != mEndpoints.end(); ++it, ++eraseIt) {
304 if (it->kInfo.id == id) {
305 mEndpoints.erase_after(eraseIt);
306 endpoint = &(*it);
307 break;
308 }
309 }
310 }
311 if (endpoint) {
312 LockGuard<Mutex> managerLock(mManagerLock);
313 CHRE_ASSERT_LOG(mManager != nullptr,
314 "The HostMessageHubManager has been destroyed.");
315 mManager->mEndpointAllocator.deallocate(endpoint);
316 }
317 }
318
onMessageReceived(pw::UniquePtr<std::byte[]> && data,uint32_t messageType,uint32_t messagePermissions,const Session & session,bool)319 bool HostMessageHubManager::Hub::onMessageReceived(
320 pw::UniquePtr<std::byte[]> &&data, uint32_t messageType,
321 uint32_t messagePermissions, const Session &session,
322 bool /*sentBySessionInitiator*/) {
323 LockGuard<Mutex> managerLock(mManagerLock);
324 if (mManager == nullptr) {
325 LOGW("The HostMessageHubManager has been destroyed.");
326 return false;
327 }
328
329 return mManager->mCb->onMessageReceived(mMessageHub.getId(),
330 session.sessionId, std::move(data),
331 messageType, messagePermissions);
332 }
333
onSessionOpenRequest(const Session & session)334 void HostMessageHubManager::Hub::onSessionOpenRequest(const Session &session) {
335 LockGuard<Mutex> managerLock(mManagerLock);
336 if (mManager == nullptr) {
337 LOGW("The HostMessageHubManager has been destroyed.");
338 return;
339 }
340
341 return mManager->mCb->onSessionOpenRequest(session);
342 }
343
onSessionOpened(const Session & session)344 void HostMessageHubManager::Hub::onSessionOpened(const Session &session) {
345 LockGuard<Mutex> managerLock(mManagerLock);
346 if (mManager == nullptr) {
347 LOGW("The HostMessageHubManager has been destroyed.");
348 return;
349 }
350
351 return mManager->mCb->onSessionOpened(mMessageHub.getId(), session.sessionId);
352 }
353
onSessionClosed(const Session & session,Reason reason)354 void HostMessageHubManager::Hub::onSessionClosed(const Session &session,
355 Reason reason) {
356 LockGuard<Mutex> managerLock(mManagerLock);
357 if (mManager == nullptr) {
358 LOGW("The HostMessageHubManager has been destroyed.");
359 return;
360 }
361
362 return mManager->mCb->onSessionClosed(mMessageHub.getId(), session.sessionId,
363 reason);
364 }
365
forEachEndpoint(const pw::Function<bool (const EndpointInfo &)> & function)366 void HostMessageHubManager::Hub::forEachEndpoint(
367 const pw::Function<bool(const EndpointInfo &)> &function) {
368 LockGuard<Mutex> lock(mEndpointsLock);
369 for (const auto &endpoint : mEndpoints)
370 if (function(endpoint.kInfo)) break;
371 }
372
getEndpointInfo(EndpointId endpointId)373 std::optional<EndpointInfo> HostMessageHubManager::Hub::getEndpointInfo(
374 EndpointId endpointId) {
375 LockGuard<Mutex> lock(mEndpointsLock);
376 for (const auto &endpoint : mEndpoints)
377 if (endpoint.kInfo.id == endpointId) return endpoint.kInfo;
378 return {};
379 }
380
getEndpointForService(const char * serviceDescriptor)381 std::optional<EndpointId> HostMessageHubManager::Hub::getEndpointForService(
382 const char *serviceDescriptor) {
383 LockGuard<Mutex> lock(mEndpointsLock);
384 for (const auto &endpoint : mEndpoints) {
385 for (const auto &service : endpoint.mServices) {
386 if (!std::strcmp(serviceDescriptor, service.serviceDescriptor))
387 return endpoint.kInfo.id;
388 }
389 }
390 return {};
391 }
392
doesEndpointHaveService(EndpointId endpointId,const char * serviceDescriptor)393 bool HostMessageHubManager::Hub::doesEndpointHaveService(
394 EndpointId endpointId, const char *serviceDescriptor) {
395 LockGuard<Mutex> lock(mEndpointsLock);
396 for (const auto &endpoint : mEndpoints) {
397 if (endpoint.kInfo.id != endpointId) continue;
398 for (const auto &service : endpoint.mServices) {
399 if (!std::strcmp(serviceDescriptor, service.serviceDescriptor))
400 return true;
401 }
402 return false;
403 }
404 return false;
405 }
406
forEachService(const pw::Function<bool (const message::EndpointInfo &,const message::ServiceInfo &)> & function)407 void HostMessageHubManager::Hub::forEachService(
408 const pw::Function<bool(const message::EndpointInfo &,
409 const message::ServiceInfo &)> &function) {
410 LockGuard<Mutex> lock(mEndpointsLock);
411 for (const auto &endpoint : mEndpoints) {
412 for (const auto &service : endpoint.mServices)
413 function(endpoint.kInfo, service);
414 }
415 }
416
onHubRegistered(const MessageHubInfo & info)417 void HostMessageHubManager::Hub::onHubRegistered(const MessageHubInfo &info) {
418 LockGuard<Mutex> managerLock(mManagerLock);
419 if (mManager == nullptr) {
420 LOGW("The HostMessageHubManager has been destroyed.");
421 return;
422 }
423
424 LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
425 mManager->mCb->onHubRegistered(info);
426 }
427
onHubUnregistered(MessageHubId id)428 void HostMessageHubManager::Hub::onHubUnregistered(MessageHubId id) {
429 LockGuard<Mutex> managerLock(mManagerLock);
430 if (mManager == nullptr) {
431 LOGW("The HostMessageHubManager has been destroyed.");
432 return;
433 }
434
435 LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
436 mManager->mCb->onHubUnregistered(id);
437 }
438
onEndpointRegistered(MessageHubId messageHubId,EndpointId endpointId)439 void HostMessageHubManager::Hub::onEndpointRegistered(MessageHubId messageHubId,
440 EndpointId endpointId) {
441 std::optional<EndpointInfo> endpoint =
442 MessageRouterSingleton::get()->getEndpointInfo(messageHubId, endpointId);
443 if (!endpoint) return;
444 LockGuard<Mutex> managerLock(mManagerLock);
445 if (mManager == nullptr) {
446 LOGW("The HostMessageHubManager has been destroyed.");
447 return;
448 }
449 LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
450
451 mManager->mCb->onEndpointRegistered(messageHubId, *endpoint);
452 struct {
453 HostCallback *cb;
454 MessageHubId hub;
455 EndpointId endpoint;
456 } context = {
457 .cb = mManager->mCb, .hub = messageHubId, .endpoint = endpointId};
458 MessageRouterSingleton::get()->forEachService(
459 [&context](const MessageHubInfo &hub, const EndpointInfo &endpoint,
460 const ServiceInfo &service) {
461 if (context.hub != hub.id) return false;
462 if (context.endpoint != endpoint.id) return false;
463 context.cb->onEndpointService(hub.id, endpoint.id, service);
464 return false;
465 });
466 mManager->mCb->onEndpointReady(messageHubId, endpointId);
467 }
468
onEndpointUnregistered(MessageHubId messageHubId,EndpointId endpointId)469 void HostMessageHubManager::Hub::onEndpointUnregistered(
470 MessageHubId messageHubId, EndpointId endpointId) {
471 LockGuard<Mutex> managerLock(mManagerLock);
472 if (mManager == nullptr) {
473 LOGW("The HostMessageHubManager has been destroyed.");
474 return;
475 }
476
477 LockGuard<Mutex> lock(mManager->mEmbeddedHubOpLock);
478 mManager->mCb->onEndpointUnregistered(messageHubId, endpointId);
479 }
480
pw_recycle()481 void HostMessageHubManager::Hub::pw_recycle() {
482 memoryFreeAndDestroy(this);
483 }
484
DoAllocate(Layout layout)485 void *HostMessageHubManager::ChreAllocator::DoAllocate(Layout layout) {
486 return memoryAlloc(layout.size());
487 }
488
DoDeallocate(void * ptr)489 void HostMessageHubManager::ChreAllocator::DoDeallocate(void *ptr) {
490 memoryFree(ptr);
491 }
492
deallocateEndpoints(pw::IntrusiveList<Endpoint> & endpoints)493 void HostMessageHubManager::deallocateEndpoints(
494 pw::IntrusiveList<Endpoint> &endpoints) {
495 while (!endpoints.empty()) {
496 auto &endpoint = endpoints.front();
497 endpoints.pop_front();
498 EventLoopManagerSingleton::get()
499 ->getHostMessageHubManager()
500 .mEndpointAllocator.deallocate(&endpoint);
501 }
502 }
503
clearHubsLocked()504 void HostMessageHubManager::clearHubsLocked() {
505 // Deactivate all existing message hubs. We need to call clear() on each hub
506 // to unregister it from MessageRouter as both MessageRouter and the
507 // HostMessageHubManager have a pw::IntrusivePtr to the Hub, which will not
508 // deallocate the Hub until both references are gone.
509 for (auto &hub : mHubs) {
510 hub->clear();
511 }
512 mHubs.clear();
513 }
514
515 } // namespace chre
516
517 #endif // CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED
518