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_CORE_CHRE_MESSAGE_HUB_MANAGER_H_ 18 #define CHRE_CORE_CHRE_MESSAGE_HUB_MANAGER_H_ 19 20 #ifdef CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED 21 22 #include "chre/platform/mutex.h" 23 #include "chre/util/dynamic_vector.h" 24 #include "chre/util/non_copyable.h" 25 #include "chre/util/system/callback_allocator.h" 26 #include "chre/util/system/message_common.h" 27 #include "chre/util/system/message_router.h" 28 #include "chre/util/system/system_callback_type.h" 29 #include "chre/util/unique_ptr.h" 30 #include "chre_api/chre.h" 31 32 #include "pw_containers/vector.h" 33 #include "pw_intrusive_ptr/recyclable.h" 34 35 #include <cstdint> 36 #include <optional> 37 38 namespace chre { 39 40 //! Manager class for the CHRE Message Hub. 41 class ChreMessageHubManager : public NonCopyable { 42 public: 43 //! The ID of the CHRE MessageHub 44 constexpr static message::MessageHubId kChreMessageHubId = CHRE_PLATFORM_ID; 45 46 ChreMessageHubManager(); 47 ~ChreMessageHubManager(); 48 49 //! Initializes the ChreMessageHubManager 50 void init(); 51 52 //! @return the MessageHub for the CHRE Message Hub getMessageHub()53 message::MessageRouter::MessageHub &getMessageHub() { 54 return mChreMessageHub; 55 } 56 57 //! Gets endpoint information for the given hub and endpoint IDs. 58 //! @return whether the endpoint information was successfully populated. 59 bool getEndpointInfo(message::MessageHubId hubId, 60 message::EndpointId endpointId, 61 chreMsgEndpointInfo &info); 62 63 //! Configures ready events for the given endpoint or service. 64 //! This function must be called from the event loop thread. 65 //! @return true if the ready events were configured successfully, false 66 //! otherwise. 67 bool configureReadyEvents(uint16_t nanoappInstanceId, 68 message::EndpointId fromEndpointId, 69 message::MessageHubId hubId, 70 message::EndpointId endpointId, 71 const char *serviceDescriptor, bool enable); 72 73 //! Gets session information for the given session ID. 74 //! @return whether the session information was successfully populated. 75 bool getSessionInfo(message::EndpointId fromEndpointId, 76 message::SessionId sessionId, chreMsgSessionInfo &info); 77 78 //! Opens a session from the given endpoint to the other endpoint in an 79 //! asynchronous manner. 80 //! @return true if the session was opened successfully, false otherwise 81 bool openSessionAsync(message::EndpointId fromEndpointId, 82 message::MessageHubId toHubId, 83 message::EndpointId toEndpointId, 84 const char *serviceDescriptor); 85 86 //! Opens a session from the given endpoint to the other endpoint in an 87 //! asynchronous manner. Either toHubId, toEndpointId, or serviceDescriptor 88 //! can be set to CHRE_MSG_HUB_ID_INVALID, ENDPOINT_ID_INVALID, or nullptr, 89 //! respectively. If they are set to invalid values, the default values will 90 //! be used if available. If no default values are available, the session will 91 //! not be opened and this function will return false. 92 //! @return true if the session was opened successfully, false otherwise 93 bool openDefaultSessionAsync(message::EndpointId fromEndpointId, 94 message::MessageHubId toHubId, 95 message::EndpointId toEndpointId, 96 const char *serviceDescriptor); 97 98 //! Closes the session and verifies the fromEndpointId is a member of the 99 //! session. 100 //! @return true if the session was closed successfully, false otherwise 101 bool closeSession(message::EndpointId fromEndpointId, 102 message::SessionId sessionId); 103 104 //! Sends a reliable message on the given session. If this function fails, 105 //! the free callback will be called and it will return false. 106 //! @return whether the message was successfully sent 107 bool sendMessage(void *message, size_t messageSize, uint32_t messageType, 108 uint16_t sessionId, uint32_t messagePermissions, 109 chreMessageFreeFunction *freeCallback, 110 message::EndpointId fromEndpointId); 111 112 //! Publishes a service from the given nanoapp. 113 //! This function must be called from the event loop thread. 114 //! @return true if the service was published successfully, false otherwise 115 bool publishServices(message::EndpointId fromEndpointId, 116 const chreMsgServiceInfo *serviceInfos, 117 size_t numServices); 118 119 //! Unregisters the given endpoint (nanoapp) from the MessageHub 120 //! This will clean up all pending resources then unregister the endpoint 121 //! from the MessageHub. 122 void unregisterEndpoint(message::EndpointId endpointId); 123 124 //! Cleans up all pending resources for the given endpoint (nanoapp). 125 //! This should only be called from the event loop thread. 126 void cleanupEndpointResources(message::EndpointId endpointId); 127 128 //! Converts a message::EndpointType to a CHRE endpoint type 129 //! @return the CHRE endpoint type 130 chreMsgEndpointType toChreEndpointType(message::EndpointType type); 131 132 //! Converts a message::Reason to a CHRE endpoint reason 133 //! @return the CHRE endpoint reason 134 chreMsgEndpointReason toChreEndpointReason(message::Reason reason); 135 136 private: 137 //! Data to be passed to the message callback 138 struct MessageCallbackData { 139 chreMsgMessageFromEndpointData messageToNanoapp; 140 pw::UniquePtr<std::byte[]> data; 141 uint64_t nanoappId; 142 }; 143 144 //! Data to be passed to the message free callback 145 struct MessageFreeCallbackData { 146 chreMessageFreeFunction *freeCallback; 147 uint64_t nanoappId; 148 }; 149 150 //! Data to be passed to the session closed callback 151 struct SessionCallbackData { 152 chreMsgSessionInfo sessionData; 153 bool isClosed; 154 uint64_t nanoappId; 155 }; 156 157 //! Data that represents a service published by a nanoapp 158 struct NanoappServiceData { 159 uint64_t nanoappId; 160 chreMsgServiceInfo serviceInfo; 161 }; 162 163 //! Data that represents a ready event configured for an endpoint or service 164 struct EndpointReadyEventData { 165 message::EndpointId fromEndpointId; 166 message::MessageHubId messageHubId; 167 message::EndpointId endpointId; 168 const char *serviceDescriptor; 169 }; 170 171 //! The callback used to register the CHRE MessageHub with the MessageRouter 172 //! @see MessageRouter::MessageHubCallback 173 class ChreMessageHubCallback 174 : public message::MessageRouter::MessageHubCallback, 175 pw::Recyclable<ChreMessageHubCallback> { 176 public: ChreMessageHubCallback(ChreMessageHubManager & manager)177 explicit ChreMessageHubCallback(ChreMessageHubManager &manager) 178 : mChreMessageHubManager(&manager) {} 179 ~ChreMessageHubCallback()180 ~ChreMessageHubCallback() { 181 clearManager(); 182 } 183 184 //! Clears the manager pointer. 185 void clearManager(); 186 187 private: 188 friend class pw::Recyclable<ChreMessageHubCallback>; 189 190 //! @see MessageRouter::MessageHubCallback 191 bool onMessageReceived(pw::UniquePtr<std::byte[]> &&data, 192 uint32_t messageType, uint32_t messagePermissions, 193 const message::Session &session, 194 bool sentBySessionInitiator) override; 195 void onSessionOpenRequest(const message::Session &session) override; 196 void onSessionOpened(const message::Session &session) override; 197 void onSessionClosed(const message::Session &session, 198 message::Reason reason) override; 199 void forEachEndpoint(const pw::Function<bool(const message::EndpointInfo &)> 200 &function) override; 201 std::optional<message::EndpointInfo> getEndpointInfo( 202 message::EndpointId endpointId) override; 203 std::optional<message::EndpointId> getEndpointForService( 204 const char *serviceDescriptor) override; 205 bool doesEndpointHaveService(message::EndpointId endpointId, 206 const char *serviceDescriptor) override; 207 void forEachService(const pw::Function<bool(const message::EndpointInfo &, 208 const message::ServiceInfo &)> 209 &function) override; 210 void onHubRegistered(const message::MessageHubInfo &info) override; 211 void onHubUnregistered(message::MessageHubId id) override; 212 void onEndpointRegistered(message::MessageHubId messageHubId, 213 message::EndpointId endpointId) override; 214 void onEndpointUnregistered(message::MessageHubId messageHubId, 215 message::EndpointId endpointId) override; 216 217 //! @see pw::Recyclable 218 void pw_recycle() override; 219 220 //! The ChreMessageHubManager that owns this callback and its lock. 221 Mutex mManagerLock; 222 ChreMessageHubManager *mChreMessageHubManager; 223 }; 224 225 friend class ChreMessageHubCallback; 226 227 constexpr static size_t kMaxFreeCallbackRecords = 25; 228 229 //! Callback to process message sent to a nanoapp - used by the event loop 230 static void onMessageToNanoappCallback( 231 SystemCallbackType type, 232 UniquePtr<ChreMessageHubManager::MessageCallbackData> &&data); 233 234 //! Callback to process session closed or opened event for a nanoapp - used 235 //! by the event loop 236 static void onSessionStateChangedCallback( 237 SystemCallbackType type, 238 UniquePtr<ChreMessageHubManager::SessionCallbackData> &&data); 239 240 //! Callback to process session open complete event - used by the event loop 241 static void onSessionOpenCompleteCallback(uint16_t type, void *data, 242 void *extraData); 243 244 //! Callback called when a message is freed 245 static void onMessageFreeCallback(std::byte *message, size_t length, 246 MessageFreeCallbackData &&callbackData); 247 248 //! Callback passed to deferCallback when handling a message free callback 249 static void handleMessageFreeCallback(uint16_t type, void *data, 250 void *extraData); 251 252 //! Called on a state change for a session - open or close. If reason is 253 //! not provided, the state change is open, else it is closed. 254 void onSessionStateChanged(const message::Session &session, 255 std::optional<message::Reason> reason); 256 257 //! Called when a session open is requested. 258 void onSessionOpenComplete(message::SessionId sessionId); 259 260 //! Processes an endpoint ready event from MessageRouter. Can only be called 261 //! from the event loop thread. 262 void onEndpointReadyEvent(message::MessageHubId messageHubId, 263 message::EndpointId endpointId); 264 265 //! @return The free callback record from the callback allocator. 266 std::optional<CallbackAllocator<MessageFreeCallbackData>::CallbackRecord> getAndRemoveFreeCallbackRecord(void * ptr)267 getAndRemoveFreeCallbackRecord(void *ptr) { 268 return mAllocator.GetAndRemoveCallbackRecord(ptr); 269 } 270 271 //! @return The first MessageHub ID for the given endpoint ID 272 message::MessageHubId findDefaultMessageHubId(message::EndpointId endpointId); 273 274 //! @return true if the nanoapp has a service with the given service 275 //! descriptor in the legacy service descriptor format. 276 bool doesNanoappHaveLegacyService(uint64_t nanoappId, uint64_t serviceId); 277 278 //! @return true if the services are valid and can be published, false 279 //! otherwise. Caller must hold mNanoappPublishedServicesMutex. 280 bool validateServicesLocked(uint64_t nanoappId, 281 const chreMsgServiceInfo *serviceInfos, 282 size_t numServices); 283 284 //! Searches for an endpoint with the given hub ID, endpoint ID, and service 285 //! descriptor. The hubId can be MESSAGE_HUB_ID_ANY to search for the 286 //! endpoint on any hub, the endpointId can be ENDPOINT_ID_ANY to search for 287 //! the endpoint on any hub, or the service descriptor can be non-nullptr to 288 //! search for any endpoint that has the service. 289 //! @return the endpoint if found, std::nullopt otherwise. 290 std::optional<message::Endpoint> searchForEndpoint( 291 message::MessageHubId messageHubId, message::EndpointId endpointId, 292 const char *serviceDescriptor); 293 294 //! Removes the ready event request for the given endpoint or service. 295 void disableReadyEvents(message::EndpointId fromEndpointId, 296 message::MessageHubId hubId, 297 message::EndpointId endpointId, 298 const char *serviceDescriptor); 299 300 //! Converts from a chreMsgEndpointServiceFormat to a message::RpcFormat. 301 //! @return the RpcFormat 302 message::RpcFormat toMessageRpcFormat(chreMsgEndpointServiceFormat format); 303 304 //! The MessageHub for the CHRE 305 message::MessageRouter::MessageHub mChreMessageHub; 306 307 //! The callback for the CHRE MessageHub 308 pw::IntrusivePtr<ChreMessageHubCallback> mChreMessageHubCallback; 309 310 //! The vector of free callback records - used by the 311 //! CallbackAllocator 312 pw::Vector<CallbackAllocator<MessageFreeCallbackData>::CallbackRecord, 313 kMaxFreeCallbackRecords> 314 mFreeCallbackRecords; 315 316 //! The allocator for message free callbacks - used when sending a message 317 //! from a nanoapp with a free callback 318 CallbackAllocator<MessageFreeCallbackData> mAllocator; 319 320 //! Mutex to protect mNanoappPublishedServices 321 Mutex mNanoappPublishedServicesMutex; 322 323 //! The vector of services published by nanoapps 324 DynamicVector<NanoappServiceData> mNanoappPublishedServices; 325 326 //! The vector of ready event requests 327 //! This should only be accessed from the event loop thread 328 DynamicVector<EndpointReadyEventData> mEndpointReadyEventRequests; 329 }; 330 331 } // namespace chre 332 333 #endif // CHRE_MESSAGE_ROUTER_SUPPORT_ENABLED 334 335 #endif // CHRE_CORE_CHRE_MESSAGE_HUB_MANAGER_H_ 336