• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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