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 #pragma once 18 19 #ifdef CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED 20 21 #include <optional> 22 23 #include "chre/platform/memory.h" 24 #include "chre/platform/mutex.h" 25 #include "chre/util/lock_guard.h" 26 #include "chre/util/memory_pool.h" 27 #include "chre/util/non_copyable.h" 28 #include "chre/util/system/message_common.h" 29 #include "chre/util/system/message_router.h" 30 31 #include "pw_allocator/allocator.h" 32 #include "pw_allocator/unique_ptr.h" 33 #include "pw_containers/intrusive_list.h" 34 #include "pw_containers/vector.h" 35 #include "pw_function/function.h" 36 #include "pw_intrusive_ptr/intrusive_ptr.h" 37 #include "pw_intrusive_ptr/recyclable.h" 38 #include "pw_span/span.h" 39 40 #if !defined(CHRE_MESSAGE_ROUTER_MAX_HOST_HUBS) 41 #error "Must define maximum host message hubs for platform" 42 #elif defined(CHRE_MESSAGE_ROUTER_MAX_MESSAGE_HUBS) && \ 43 CHRE_MESSAGE_ROUTER_MAX_HOST_HUBS >= CHRE_MESSAGE_ROUTER_MAX_MESSAGE_HUBS 44 #error "Message hub limit must be greater than host message hub limit" 45 #endif // !defined(CHRE_MESSAGE_ROUTER_MAX_HOST_HUBS) 46 47 #ifndef CHRE_MESSAGE_ROUTER_MAX_HOST_ENDPOINTS 48 #error "Must define maximum host endpoints for platform" 49 #endif // CHRE_MESSAGE_ROUTER_MAX_HOST_ENDPOINTS 50 51 namespace chre { 52 53 /** 54 * Manages the registration of host-side message hubs with MessageRouter and 55 * routes messages between them. 56 */ 57 class HostMessageHubManager : public NonCopyable { 58 public: 59 /** Interface registered for routing communication to host hubs. */ 60 class HostCallback { 61 public: 62 virtual ~HostCallback() = default; 63 64 /** 65 * Notifies the HAL that the host message hub proxies have been reset. 66 * 67 * Invoked within MessageHubManager::reset(). 68 */ 69 virtual void onReset() = 0; 70 71 /** 72 * Notifies the HAL of a new embedded message hub. 73 */ 74 virtual void onHubRegistered(const message::MessageHubInfo &hub) = 0; 75 76 /** 77 * Notifies the HAL that an embedded hub has been removed. 78 */ 79 virtual void onHubUnregistered(message::MessageHubId id) = 0; 80 81 /** 82 * Notifies the HAL of a new embedded endpoint. 83 */ 84 virtual void onEndpointRegistered( 85 message::MessageHubId hub, const message::EndpointInfo &endpoint) = 0; 86 87 /** 88 * Adds a service for a new embedded endpoint. 89 */ 90 virtual void onEndpointService(message::MessageHubId hub, 91 const message::EndpointId endpoint, 92 const message::ServiceInfo &service) = 0; 93 94 /** 95 * Notifies the HAL that it has all information on an embedded endpoint. 96 */ 97 virtual void onEndpointReady(message::MessageHubId hub, 98 message::EndpointId endpoint) = 0; 99 100 /** 101 * Notifies the HAL that an embedded endpoint is gone. 102 */ 103 virtual void onEndpointUnregistered(message::MessageHubId hub, 104 message::EndpointId endpoint) = 0; 105 106 /** 107 * Sends a message within a session. 108 * 109 * Invoked within MessageHubCallback::onMessageReceived(). 110 * 111 * @param hub The destination hub id 112 * @param session The session id 113 * @param data Message data 114 * @param type Message type 115 * @param permissions Message permissiosn 116 * @return true if the message was successfully sent 117 */ 118 virtual bool onMessageReceived(message::MessageHubId hub, 119 message::SessionId session, 120 pw::UniquePtr<std::byte[]> &&data, 121 uint32_t type, uint32_t permissions) = 0; 122 /** 123 * Sends a request to open a session with a host endpoint 124 * 125 * Invoked within MessageHubCallback::onSessionOpenRequest(). 126 * 127 * @param session The session details 128 */ 129 virtual void onSessionOpenRequest(const message::Session &session) = 0; 130 131 /** 132 * Sends a notification that a session has been accepted 133 * 134 * Invoked within MessageHubCallback::onSessionOpened(). 135 * 136 * @param hub The id of the destination host hub 137 * @param session The session id 138 */ 139 virtual void onSessionOpened(message::MessageHubId hub, 140 message::SessionId session) = 0; 141 142 /** 143 * Sends a notification that a session has been closed 144 * 145 * Invoked within MessageHubCallback::onSessionClosed(). 146 * 147 * @param hub The id of the destination host hub 148 * @param session The session id 149 * @param reason The reason the session has been closed 150 */ 151 virtual void onSessionClosed(message::MessageHubId hub, 152 message::SessionId session, 153 message::Reason reason) = 0; 154 }; 155 156 HostMessageHubManager() = default; 157 ~HostMessageHubManager(); 158 159 /** 160 * Initializes the interface for host communication 161 * 162 * Must be called exactly once before any other HostMessageHubManager APIs. 163 * 164 * @param cb Implementation of HostCallback 165 */ 166 void onHostTransportReady(HostCallback &cb); 167 168 /** 169 * Resets host message hub state. 170 * 171 * Existing message hubs are cleared (see Hub::clear() below) though they 172 * remain registered with MessageRouter. When the same hub is registered again 173 * the same slot is re-activated. 174 */ 175 void reset(); 176 177 /** 178 * Registers a new host message hub 179 * 180 * @param info Details of the message hub 181 */ 182 void registerHub(const message::MessageHubInfo &info); 183 184 /** 185 * Unregisters a host message hub 186 * 187 * @param id Id of the message hub 188 */ 189 void unregisterHub(message::MessageHubId id); 190 191 /** 192 * Registers a host endpoint 193 * 194 * @param hubId Id of the owning message hub 195 * @param info Details of the endpoint 196 * @param services Services exposed by the endpoint. NOTE: serviceDescriptor 197 * must have been allocated with CHRE platform memoryAlloc(). 198 */ 199 void registerEndpoint(message::MessageHubId hubId, 200 const message::EndpointInfo &info, 201 DynamicVector<message::ServiceInfo> &&services); 202 203 /** 204 * Unregisters a host endpoint 205 * 206 * @param hubId Id of the owning message hub 207 * @param id Id of the endpoint 208 */ 209 void unregisterEndpoint(message::MessageHubId hubId, message::EndpointId id); 210 211 /** 212 * Requests the creation of a new session 213 * 214 * @param hubId Id of the host hub 215 * @param endpointId Id of the host endpoint 216 * @param destinationHubId Id of the destination hub 217 * @param destinationEndpointId Id of the destination endpoint 218 * @param sessionId Id of the new session 219 * @param serviceDescriptor The protocol for the session (maybe nullptr) 220 */ 221 void openSession(message::MessageHubId hubId, message::EndpointId endpointId, 222 message::MessageHubId destinationHubId, 223 message::EndpointId destinationEndpointId, 224 message::SessionId sessionId, const char *serviceDescriptor); 225 226 /** 227 * Notifies that a new session has been accepted 228 * 229 * @param hubId Id of the sending host hub 230 * @param sessionId Id of the new session 231 */ 232 void ackSession(message::MessageHubId hubId, message::SessionId sessionId); 233 234 /** 235 * Notifies that a session has been closed / rejected 236 * 237 * @param hubId Id of the sending host hub 238 * @param sessionId Id of the session 239 * @param reason The reason for the closure / rejection 240 */ 241 void closeSession(message::MessageHubId hubId, message::SessionId sessionId, 242 message::Reason reason); 243 244 /** 245 * Sends a message within a session 246 * 247 * @param hubId Id of the sending host hub 248 * @param sessionId Id of the session 249 * @param data Message data 250 * @param type Message type 251 * @param permissions Message permissions 252 */ 253 void sendMessage(message::MessageHubId hubId, message::SessionId sessionId, 254 pw::span<const std::byte> data, uint32_t type, 255 uint32_t permissions); 256 257 private: 258 /** 259 * Wrapper around EndpointInfo and ServiceInfos which can be allocated from a 260 * pw::allocator::TypedPool and tracked per-hub in a pw::IntrusiveList. The 261 * serviceDescriptors must have been allocated by memoryAlloc() from 262 * chre/platform/memory.h. 263 */ 264 struct Endpoint : public pw::IntrusiveList<Endpoint>::Item { 265 message::EndpointInfo kInfo; 266 DynamicVector<message::ServiceInfo> mServices; EndpointEndpoint267 explicit Endpoint(const message::EndpointInfo &info, 268 DynamicVector<message::ServiceInfo> &&services) 269 : kInfo(info), mServices(std::move(services)) {} ~EndpointEndpoint270 ~Endpoint() { 271 for (const auto &service : mServices) 272 memoryFree(const_cast<char *>(service.serviceDescriptor)); 273 } 274 }; 275 276 /** 277 * Represents a host message hub. Registered with MessageRouter and stores the 278 * returned MessageRouter::MessageHub. Stores the list of registered endpoints 279 * for inspection by MessageRouter. 280 * 281 * The public APIs are expected to be called as a result of some host-side 282 * operation with HostMessageHubManager::mHubsLock held. 283 */ 284 class Hub : public NonCopyable, 285 public message::MessageRouter::MessageHubCallback, 286 public pw::Recyclable<Hub> { 287 public: 288 /** 289 * Creates and registers a new hub. 290 * 291 * @param manager The manager instance 292 * @param info Details of the host message hub 293 * @param endpoints The list of endpoints to initialize the hub with. 294 * Endpoints must have been allocated using mEndpointAllocator. 295 * @return true on successful registration or reactivation 296 */ 297 static bool createLocked(HostMessageHubManager *manager, 298 const message::MessageHubInfo &info, 299 pw::IntrusiveList<Endpoint> &endpoints); 300 301 /** NOTE: Use createLocked() */ 302 Hub(HostMessageHubManager *manager, const char *name, 303 pw::IntrusiveList<Endpoint> &endpoints); 304 Hub(Hub &&) = delete; 305 Hub &operator=(Hub &&) = delete; 306 virtual ~Hub(); 307 308 /** 309 * Marks the hub inactive and clears all endpoints. Also unregisters the 310 * hub from MessageRouter. 311 */ 312 void clear(); 313 314 void addEndpoint(const message::EndpointInfo &info, 315 DynamicVector<message::ServiceInfo> &&services); 316 317 void removeEndpoint(message::EndpointId id); 318 getMessageHub()319 message::MessageRouter::MessageHub &getMessageHub() { 320 return mMessageHub; 321 } 322 323 private: 324 friend class pw::Recyclable<Hub>; 325 326 static constexpr size_t kNameMaxLen = 50; 327 328 // Implementation of MessageRouter::MessageHubCallback; 329 bool onMessageReceived(pw::UniquePtr<std::byte[]> &&data, 330 uint32_t messageType, uint32_t messagePermissions, 331 const message::Session &session, 332 bool sentBySessionInitiator) override; 333 void onSessionOpenRequest(const message::Session &session) override; 334 void onSessionOpened(const message::Session &session) override; 335 void onSessionClosed(const message::Session &session, 336 message::Reason reason) override; 337 void forEachEndpoint(const pw::Function<bool(const message::EndpointInfo &)> 338 &function) override; 339 std::optional<message::EndpointInfo> getEndpointInfo( 340 message::EndpointId endpointId) override; 341 std::optional<message::EndpointId> getEndpointForService( 342 const char *serviceDescriptor) override; 343 bool doesEndpointHaveService(message::EndpointId endpointId, 344 const char *serviceDescriptor) override; 345 void forEachService(const pw::Function<bool(const message::EndpointInfo &, 346 const message::ServiceInfo &)> 347 &function) override; 348 void onHubRegistered(const message::MessageHubInfo &info) override; 349 void onHubUnregistered(message::MessageHubId id) override; 350 void onEndpointRegistered(message::MessageHubId messageHubId, 351 message::EndpointId endpointId) override; 352 void onEndpointUnregistered(message::MessageHubId messageHubId, 353 message::EndpointId endpointId) override; 354 void pw_recycle() override; 355 356 char kName[kNameMaxLen + 1]; 357 358 message::MessageRouter::MessageHub mMessageHub; 359 360 // The manager pointer and lock. 361 Mutex mManagerLock; 362 HostMessageHubManager *mManager; 363 364 // Guards mEndpoints. Must be the innermost lock. 365 Mutex mEndpointsLock; 366 pw::IntrusiveList<Endpoint> mEndpoints; 367 }; 368 369 /** 370 * Trivial allocator wrapping the CHRE memory allocation platform APIs. It 371 * spits out pw::UniquePtr<std::byte> instances which can be passed to 372 * MessageRouter APIs. 373 */ 374 // TODO(b/395649065): Move this into util 375 class ChreAllocator : public pw::Allocator { 376 public: 377 void *DoAllocate(Layout layout) override; 378 void DoDeallocate(void *ptr) override; 379 }; 380 381 // Consumes and deallocates all entries in the list. Caller must ensure 382 // the HostMessageHubManager has not been destroyed. 383 static void deallocateEndpoints(pw::IntrusiveList<Endpoint> &endpoints); 384 385 /** 386 * Clears all hubs registered with MessageRouter. The caller must hold 387 * mHubsLock. 388 */ 389 void clearHubsLocked(); 390 391 HostCallback *mCb; 392 ChreAllocator mMsgAllocator; 393 394 // Endpoint storage and allocator. 395 // NOTE: This is only accessed on host-triggered invocations which take 396 // mHubsLock, so additional synchronization is not required. 397 MemoryPool<Endpoint, CHRE_MESSAGE_ROUTER_MAX_HOST_ENDPOINTS> 398 mEndpointAllocator; 399 400 // Guards mHubs. This lock is only safe to take when coming from an external 401 // path, i.e. on message from the host. MessageRouter accesses Hub instances 402 // directly, i.e. not through mHubs via the registered MessageHubCallback 403 // interface. 404 Mutex mHubsLock; 405 pw::Vector<pw::IntrusivePtr<Hub>, CHRE_MESSAGE_ROUTER_MAX_HOST_HUBS> mHubs; 406 407 // Serializes embedded hub and endpoint state changes being sent to the host 408 // with the operations in reset(). 409 Mutex mEmbeddedHubOpLock; 410 }; 411 412 } // namespace chre 413 414 #endif // CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED 415