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