xref: /aosp_15_r20/system/chre/util/include/chre/util/system/message_router.h (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 #ifndef CHRE_UTIL_SYSTEM_MESSAGE_ROUTER_H_
18 #define CHRE_UTIL_SYSTEM_MESSAGE_ROUTER_H_
19 
20 #include <pw_allocator/unique_ptr.h>
21 #include <pw_containers/vector.h>
22 #include <pw_function/function.h>
23 #include <cstddef>
24 #include <cstdint>
25 #include <optional>
26 
27 #include "chre/platform/mutex.h"
28 #include "chre/util/singleton.h"
29 #include "chre/util/system/message_common.h"
30 
31 namespace chre::message {
32 
33 //! MessageRouter routes messages between endpoints connected to MessageHubs. It
34 //! provides an API for registering MessageHubs, opening and closing sessions,
35 //! and sending messages between endpoints. Each MessageHub is expected to
36 //! register a callback to handle messages sent to its endpoints and other
37 //! functions to provide information about the endpoints connected to it.
38 //!
39 //! MessageRouter is thread-safe.
40 //!
41 //! Usage:
42 //! 1. Create a MessageRouter instance.
43 //! 2. Register MessageHubs with the MessageRouter. Each MessageHub must have
44 //!    a unique ID and a callback to handle messages sent to its endpoints.
45 //! 3. Open sessions from endpoints connected to MessageHubs to endpoints
46 //!    connected to other MessageHubs.
47 //! 4. Send messages to endpoints using the MessageRouter API.
48 //! 5. Close sessions when they are no longer needed.
49 class MessageRouter {
50  public:
51   //! The callback used to register a MessageHub with the MessageRouter
52   class MessageHubCallback {
53    public:
54     virtual ~MessageHubCallback() = default;
55 
56     //! Message processing callback. If this function returns true,
57     //! the MessageHub received the message and will deliver it to the
58     //! receiving endpoint, or close the session if an error occurs.
59     //! @see sendMessage
60     //! @param session The session that the message was sent on (this reference
61     //!                is only valid for the duration of the callback)
62     //! @param sentBySessionInitiator Whether the message was sent by the
63     //! initiator of the session
64     //! @return true if the message was accepted for processing
65     virtual bool onMessageReceived(pw::UniquePtr<std::byte[]> &&data,
66                                    size_t length, uint32_t messageType,
67                                    uint32_t messagePermissions,
68                                    const Session &session,
69                                    bool sentBySessionInitiator) = 0;
70 
71     //! Callback called when the session is closed
72     virtual void onSessionClosed(const Session &session) = 0;
73 
74     //! Callback called to iterate over all endpoints connected to the
75     //! MessageHub. Underlying endpoint storage must not change during this
76     //! callback. If function returns true, the MessageHub can stop iterating
77     //! over future endpoints. This function should not call any MessageRouter
78     //! or MessageHub functions.
79     virtual void forEachEndpoint(
80         const pw::Function<bool(const EndpointInfo &)> &function) = 0;
81 
82     //! @return The EndpointInfo for the given endpoint ID. This function should
83     //! not call any MessageRouter or MessageHub functions.
84     virtual std::optional<EndpointInfo> getEndpointInfo(
85         EndpointId endpointId) = 0;
86   };
87 
88   //! The API returned when registering a MessageHub with the MessageRouter.
89   class MessageHub {
90    public:
91     //! Creates an empty MessageHub that is not usable, similar to a moved-from
92     //! MessageHub. Attempting to call any method on this object results in
93     //! undefined behavior.
94     MessageHub();
95 
~MessageHub()96     ~MessageHub() {
97       if (mRouter != nullptr) {
98         mRouter->unregisterMessageHub(mHubId);
99       }
100     }
101     // There can only be one live MessageHub instance for a given hub ID, so
102     // only move operations are supported.
103     MessageHub(const MessageHub &) = delete;
104     MessageHub &operator=(const MessageHub &) = delete;
105     MessageHub(MessageHub &&other);
106     MessageHub &operator=(MessageHub &&other);
107 
108     //! Opens a session from an endpoint connected to the current MessageHub
109     //! to the listed MessageHub ID and endpoint ID
110     //! @return The session ID or SESSION_ID_INVALID if the session could
111     //! not be opened
112     SessionId openSession(EndpointId fromEndpointId,
113                           MessageHubId toMessageHubId, EndpointId toEndpointId);
114 
115     //! Closes the session with sessionId
116     //! @return true if the session was closed, false if the session was not
117     //! found
118     bool closeSession(SessionId sessionId);
119 
120     //! Returns a session if it exists
121     //! @return The session or std::nullopt if the session was not found
122     std::optional<Session> getSessionWithId(SessionId sessionId);
123 
124     //! Sends a message to the session specified by sessionId.
125     //! @see chreSendReliableMessageAsync. Sends the message in a reliable
126     //! manner if possible. If the message cannot be delivered, the session
127     //! is closed and subsequent calls to this function with the same sessionId
128     //! will return false.
129     //! @param data The data to send
130     //! @param length The length of the data to send
131     //! @param messageType The type of the message, a bit flagged value
132     //! @param messagePermissions The permissions of the message, a bit flagged
133     //! value
134     //! @param sessionId The session to send the message on
135     //! @return true if the message was sent, false if the message could not be
136     //! sent
137     bool sendMessage(pw::UniquePtr<std::byte[]> &&data, size_t length,
138                      uint32_t messageType, uint32_t messagePermissions,
139                      SessionId sessionId);
140 
141     //! @return The MessageHub ID of the currently connected MessageHub
142     MessageHubId getId();
143 
144    private:
145     friend class MessageRouter;
146 
147     MessageHub(MessageRouter &router, MessageHubId id);
148 
149     //! The MessageRouter that this MessageHub is connected to
150     MessageRouter *mRouter;
151 
152     //! The id of this message hub
153     MessageHubId mHubId;
154   };
155 
156   //! Represents a MessageHub and its connected endpoints
157   struct MessageHubRecord {
158     MessageHubInfo info;
159     MessageHubCallback *callback;
160   };
161 
162   MessageRouter() = delete;
MessageRouter(pw::Vector<MessageHubRecord> & messageHubs,pw::Vector<Session> & sessions)163   MessageRouter(pw::Vector<MessageHubRecord> &messageHubs,
164                 pw::Vector<Session> &sessions)
165       : mMessageHubs(messageHubs), mSessions(sessions) {}
166 
167   //! Registers a MessageHub with the MessageRouter.
168   //! The provided name must be unique and not registered before and be a valid
169   //! C string. The data underlying name must outlive the MessageHub. The
170   //! callback must outlive the MessageHub. The ID must be unique and not
171   //! registered before. When the returned MessageHub is destroyed, it will
172   //! unregister itself from the MessageRouter.
173   //! @param name The name of the MessageHub
174   //! @param id The ID of the MessageHub
175   //! @param callback The callback to handle messages sent to the MessageHub
176   //! @return The MessageHub API or std::nullopt if the MessageHub could not be
177   //! registered
178   std::optional<MessageHub> registerMessageHub(const char *name,
179                                                MessageHubId id,
180                                                MessageHubCallback &callback);
181 
182   //! Executes the function for each endpoint connected to this MessageHub.
183   //! If function returns true, the iteration will stop.
184   //! @return true if the MessageHub is found, false otherwise
185   bool forEachEndpointOfHub(
186       MessageHubId messageHubId,
187       const pw::Function<bool(const EndpointInfo &)> &function);
188 
189   //! Executes the function for each endpoint connected to all Message Hubs.
190   //! The lock is held when calling the callback.
191   void forEachEndpoint(
192       const pw::Function<void(const MessageHubInfo &, const EndpointInfo &)>
193           &function);
194 
195   //! @return The EndpointInfo for the given hub and endpoint IDs
196   std::optional<EndpointInfo> getEndpointInfo(MessageHubId messageHubId,
197                                               EndpointId endpointId);
198 
199   //! Executes the function for each MessageHub connected to the MessageRouter.
200   //! If function returns true, the iteration will stop.
201   //! The lock is held when calling the callback.
202   void forEachMessageHub(
203       const pw::Function<bool(const MessageHubInfo &)> &function);
204 
205  private:
206   //! Unregisters a MessageHub from the MessageRouter. This function will
207   //! close all sessions that were initiated by or connected to the MessageHub
208   //! and destroy the MessageHubRecord. This function will call the callback
209   //! for each session that was closed only for the other message hub in the
210   //! session.
211   //! @return true if the MessageHub was unregistered, false if the MessageHub
212   //! was not found.
213   bool unregisterMessageHub(MessageHubId fromMessageHubId);
214 
215   //! Opens a session from an endpoint connected to the current MessageHub
216   //! to the listed MessageHub ID and endpoint ID
217   //! @return The session ID or SESSION_ID_INVALID if the session could not be
218   //! opened
219   SessionId openSession(MessageHubId fromMessageHubId,
220                         EndpointId fromEndpointId, MessageHubId toMessageHubId,
221                         EndpointId toEndpointId);
222 
223   //! Closes the session with sessionId
224   //! @return true if the session was closed, false if the session was not
225   //! found
226   bool closeSession(MessageHubId fromMessageHubId, SessionId sessionId);
227 
228   //! Returns a session if it exists
229   //! @return The session or std::nullopt if the session was not found
230   std::optional<Session> getSessionWithId(MessageHubId fromMessageHubId,
231                                           SessionId sessionId);
232 
233   //! Sends a message to the session specified by sessionId.
234   //! @see chreSendReliableMessageAsync. Sends the message in a reliable
235   //! manner if possible. If the message cannot be delivered, the session
236   //! is closed and subsequent calls to this function with the same sessionId
237   //! will return false.
238   //! @see MessageHub::sendMessage
239   //! @return true if the message was sent, false if the message could not be
240   //! sent
241   bool sendMessage(pw::UniquePtr<std::byte[]> &&data, size_t length,
242                    uint32_t messageType, uint32_t messagePermissions,
243                    SessionId sessionId, MessageHubId fromMessageHubId);
244 
245   //! @return The MessageHubRecord for the given MessageHub ID
246   const MessageHubRecord *getMessageHubRecordLocked(MessageHubId messageHubId);
247 
248   //! @return The index of the session if it exists
249   //! Requires the caller to hold the mutex
250   std::optional<size_t> findSessionIndexLocked(MessageHubId fromMessageHubId,
251                                                SessionId sessionId);
252 
253   //! @return The callback for the given MessageHub ID or nullptr if not found
254   //! Requires the caller to hold the mutex
255   MessageHubCallback *getCallbackFromMessageHubId(MessageHubId messageHubId);
256 
257   //! @return The callback for the given MessageHub ID or nullptr if not found
258   MessageHubCallback *getCallbackFromMessageHubIdLocked(
259       MessageHubId messageHubId);
260 
261   //! @return true if the endpoint exists in the MessageHub with the given
262   //! callback
263   bool checkIfEndpointExists(MessageHubCallback *callback, EndpointId endpointId);
264 
265   //! The mutex to protect MessageRouter state
266   Mutex mMutex;
267 
268   //! The next available Session ID
269   SessionId mNextSessionId = 0;
270 
271   //! The list of MessageHubs connected to the MessageRouter
272   pw::Vector<MessageHubRecord> &mMessageHubs;
273 
274   //! The list of sessions connected to the MessageRouter
275   pw::Vector<Session> &mSessions;
276 };
277 
278 //! Define the singleton instance of the MessageRouter
279 typedef Singleton<MessageRouter> MessageRouterSingleton;
280 
281 //! Routes messages between MessageHubs
282 template <size_t kMaxMessageHubs, size_t kMaxSessions>
283 class MessageRouterWithStorage : public MessageRouter {
284  public:
MessageRouterWithStorage()285   MessageRouterWithStorage():
286       MessageRouter(mMessageHubs, mSessions) {}
287 
288  private:
289   //! The list of MessageHubs connected to the MessageRouter
290   pw::Vector<MessageHubRecord, kMaxMessageHubs> mMessageHubs;
291 
292   //! The list of sessions connected to the MessageRouter
293   pw::Vector<Session, kMaxSessions> mSessions;
294 };
295 
296 }  // namespace chre::message
297 
298 #endif  // CHRE_UTIL_SYSTEM_MESSAGE_ROUTER_H_
299