1 /* 2 * Copyright (C) 2022 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 #ifndef ANDROID_HARDWARE_CONTEXTHUB_COMMON_HAL_CLIENT_MANAGER_H_ 17 #define ANDROID_HARDWARE_CONTEXTHUB_COMMON_HAL_CLIENT_MANAGER_H_ 18 19 #include <aidl/android/hardware/contexthub/ContextHubMessage.h> 20 #include <aidl/android/hardware/contexthub/IContextHub.h> 21 #include <aidl/android/hardware/contexthub/IContextHubCallback.h> 22 #include <chre_host/fragmented_load_transaction.h> 23 #include <chre_host/preloaded_nanoapp_loader.h> 24 #include <sys/types.h> 25 #include <cstddef> 26 #include <unordered_map> 27 #include <unordered_set> 28 #include "chre_host/log.h" 29 #include "hal_client_id.h" 30 31 using aidl::android::hardware::contexthub::ContextHubMessage; 32 using aidl::android::hardware::contexthub::HostEndpointInfo; 33 using aidl::android::hardware::contexthub::IContextHubCallback; 34 using android::chre::FragmentedLoadTransaction; 35 using HostEndpointId = uint16_t; 36 37 namespace android::hardware::contexthub::common::implementation { 38 39 /** 40 * A class managing clients for Context Hub HAL. 41 * 42 * A HAL client is defined as a user calling the IContextHub API. The main 43 * purpose of this class are: 44 * - to assign a unique HalClientId identifying each client; 45 * - to maintain a mapping between client ids and HalClientInfos; 46 * - to maintain a mapping between client ids and their endpoint ids. 47 * 48 * There are two types of ids HalClientManager will track, host endpoint id and 49 * client id. A host endpoint id, which is defined at 50 * hardware/interfaces/contexthub/aidl/android/hardware/contexthub/ContextHubMessage.aidl, 51 * identifies a host app that communicates with a HAL client. A client id 52 * identifies a HAL client, which is the layer beneath the host apps, such as 53 * ContextHubService. Multiple apps with different host endpoint IDs can have 54 * the same client ID. 55 * 56 * For a host endpoint connected to ContextHubService, its endpoint id is kept 57 *in the form below during the communication with CHRE. 58 * 59 * 0 1 60 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 61 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 62 * |0| endpoint_id | 63 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 64 * 65 * For vendor host endpoints, the client id is embedded into the endpoint id 66 * before sending a message to CHRE. When that happens, the highest bit is set 67 * to 1 and the endpoint id is mutated to the format below: 68 * 69 * 0 1 70 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 71 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 72 * |1| client_id |endpoint_id| 73 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 74 * 75 * Note that HalClientManager is not responsible for generating endpoint ids, 76 * which should be managed by HAL clients themselves. 77 */ 78 class HalClientManager { 79 public: 80 HalClientManager(); 81 virtual ~HalClientManager() = default; 82 83 /** Disable copy constructor and copy assignment to avoid duplicates. */ 84 HalClientManager(HalClientManager &) = delete; 85 void operator=(const HalClientManager &) = delete; 86 87 /** 88 * Gets the client id allocated to the current HAL client. 89 * 90 * The current HAL client is identified by its process id, which is retrieved 91 * by calling AIBinder_getCallingPid(). If the process doesn't have any client 92 * id assigned, HalClientManager will create one mapped to its process id. 93 * 94 * @return client id assigned to the calling process, or kDefaultHalClientId 95 * if the process id is not found. 96 */ 97 HalClientId getClientId(); 98 99 /** 100 * Gets the callback for the current HAL client identified by the clientId. 101 * 102 * @return callback previously registered. nullptr is returned if the clientId 103 * is not found. 104 */ 105 std::shared_ptr<IContextHubCallback> getCallback(HalClientId clientId); 106 107 /** 108 * Registers a IContextHubCallback function mapped to the current client's 109 * client id. @p deathRecipient and @p deathRecipientCookie are used to unlink 110 * the previous registered callback for the same client, if any. 111 * 112 * @param callback a function incurred to handle the client death event. 113 * @param deathRecipient a handle on the death notification. 114 * @param deathRecipientCookie the data used by the callback. 115 * 116 * @return true if success, otherwise false. 117 */ 118 bool registerCallback( 119 const std::shared_ptr<IContextHubCallback> &callback, 120 const ndk::ScopedAIBinder_DeathRecipient &deathRecipient, 121 void *deathRecipientCookie); 122 123 /** 124 * Registers a FragmentedLoadTransaction for the current HAL client. 125 * 126 * At this moment only one active transaction, either load or unload, is 127 * supported. 128 * 129 * @return true if success, otherwise false. 130 */ 131 bool registerPendingLoadTransaction( 132 std::unique_ptr<FragmentedLoadTransaction> transaction); 133 134 /** 135 * Returns true if the load transaction matches the arguments provided. 136 */ isPendingLoadTransactionExpected(HalClientId clientId,uint32_t transactionId,uint32_t currentFragmentId)137 bool isPendingLoadTransactionExpected(HalClientId clientId, 138 uint32_t transactionId, 139 uint32_t currentFragmentId) { 140 const std::lock_guard<std::mutex> lock(mLock); 141 return isPendingLoadTransactionMatchedLocked(clientId, transactionId, 142 currentFragmentId); 143 } 144 145 /** 146 * Clears the pending load transaction. 147 * 148 * This function is called to proactively clear out a pending load transaction 149 * that is not timed out yet. 150 * 151 */ 152 void resetPendingLoadTransaction(); 153 154 /** 155 * Gets the next FragmentedLoadRequest from PendingLoadTransaction if it's 156 * available. 157 * 158 * @return an optional FragmentedLoadRequest, std::nullopt if unavailable. 159 */ 160 161 std::optional<chre::FragmentedLoadRequest> getNextFragmentedLoadRequest(); 162 163 /** 164 * Registers the current HAL client as having a pending unload transaction. 165 * 166 * At this moment only one active transaction, either load or unload, is 167 * supported. 168 * 169 * @return true if success, otherwise false. 170 */ 171 bool registerPendingUnloadTransaction(uint32_t transactionId); 172 173 /** 174 * Clears the pending unload transaction. 175 * 176 * This function is called to proactively clear out a pending unload 177 * transaction that is not timed out yet. @p clientId and @p 178 * transactionId must match the existing pending transaction. 179 * 180 * @param clientId the client id of the caller. 181 * @param transactionId unique id of the transaction. 182 * 183 * @return true if the pending transaction is cleared, otherwise false. 184 */ 185 bool resetPendingUnloadTransaction(HalClientId clientId, 186 uint32_t transactionId); 187 188 /** 189 * Registers an endpoint id when it is connected to HAL. 190 * 191 * @return true if success, otherwise false. 192 */ 193 bool registerEndpointId(const HostEndpointId &endpointId); 194 195 /** 196 * Removes an endpoint id when it is disconnected to HAL. 197 * 198 * @return true if success, otherwise false. 199 */ 200 bool removeEndpointId(const HostEndpointId &endpointId); 201 202 /** 203 * Mutates the endpoint id if the hal client is not the framework service. 204 * 205 * @return true if success, otherwise false. 206 */ 207 bool mutateEndpointIdFromHostIfNeeded(const pid_t &pid, 208 HostEndpointId &endpointId); 209 210 /** Returns the original endpoint id sent by the host client. */ 211 static HostEndpointId convertToOriginalEndpointId( 212 const HostEndpointId &endpointId); 213 214 /** 215 * Gets all the connected endpoints for the client identified by the pid. 216 * 217 * @return the pointer to the endpoint id set if the client is identifiable, 218 * otherwise nullptr. 219 */ 220 const std::unordered_set<HostEndpointId> *getAllConnectedEndpoints(pid_t pid); 221 222 /** Sends a message to every connected endpoints. */ 223 void sendMessageForAllCallbacks( 224 const ContextHubMessage &message, 225 const std::vector<std::string> &messageParams); 226 227 std::shared_ptr<IContextHubCallback> getCallbackForEndpoint( 228 const HostEndpointId &endpointId); 229 230 /** 231 * Handles the client death event. 232 * 233 * @param pid of the client that loses the binder connection to the HAL. 234 * @param deathRecipient to be unlinked with the client's callback 235 */ 236 void handleClientDeath( 237 pid_t pid, const ndk::ScopedAIBinder_DeathRecipient &deathRecipient); 238 239 /** Handles CHRE restart event. */ 240 void handleChreRestart(); 241 242 protected: 243 static constexpr char kSystemServerName[] = "system_server"; 244 static constexpr char kClientMappingFilePath[] = 245 "/data/vendor/chre/chre_hal_clients.json"; 246 static constexpr char kJsonClientId[] = "ClientId"; 247 static constexpr char kJsonProcessName[] = "ProcessName"; 248 static constexpr int64_t kTransactionTimeoutThresholdMs = 5000; // 5 seconds 249 static constexpr uint8_t kNumOfBitsForEndpointId = 6; 250 static constexpr HostEndpointId kMaxVendorEndpointId = 251 (1 << kNumOfBitsForEndpointId) - 1; 252 // The endpoint id is from a vendor client if the highest bit is set to 1. 253 static constexpr HostEndpointId kVendorEndpointIdBitMask = 0x8000; 254 255 struct HalClientInfo { HalClientInfoHalClientInfo256 explicit HalClientInfo(const std::shared_ptr<IContextHubCallback> &callback, 257 void *cookie) { 258 this->callback = callback; 259 this->deathRecipientCookie = cookie; 260 } 261 HalClientInfo() = default; 262 std::shared_ptr<IContextHubCallback> callback; 263 // cookie is used by the death recipient's linked callback 264 void *deathRecipientCookie{}; 265 std::unordered_set<HostEndpointId> endpointIds{}; 266 }; 267 268 struct PendingTransaction { PendingTransactionPendingTransaction269 PendingTransaction(HalClientId clientId, uint32_t transactionId, 270 int64_t registeredTimeMs) { 271 this->clientId = clientId; 272 this->transactionId = transactionId; 273 this->registeredTimeMs = registeredTimeMs; 274 } 275 HalClientId clientId; 276 uint32_t transactionId; 277 int64_t registeredTimeMs; 278 }; 279 280 /** 281 * PendingLoadTransaction tracks ongoing load transactions. 282 */ 283 struct PendingLoadTransaction : public PendingTransaction { PendingLoadTransactionPendingLoadTransaction284 PendingLoadTransaction( 285 HalClientId clientId, int64_t registeredTimeMs, 286 uint32_t currentFragmentId, 287 std::unique_ptr<chre::FragmentedLoadTransaction> transaction) 288 : PendingTransaction(clientId, transaction->getTransactionId(), 289 registeredTimeMs) { 290 this->currentFragmentId = currentFragmentId; 291 this->transaction = std::move(transaction); 292 } 293 uint32_t currentFragmentId; // the fragment id being sent out. 294 std::unique_ptr<chre::FragmentedLoadTransaction> transaction; 295 toStringPendingLoadTransaction296 [[nodiscard]] std::string toString() const { 297 using android::internal::ToString; 298 return "[Load transaction: client id " + ToString(clientId) + 299 ", Transaction id " + ToString(transaction->getTransactionId()) + 300 ", fragment id " + ToString(currentFragmentId) + "]"; 301 } 302 }; 303 304 /** 305 * Creates a client id to uniquely identify a HAL client. 306 * 307 * A file is maintained on the device for the mappings between client names 308 * and client ids so that if a client has connected to HAL before the same 309 * client id is always assigned to it. 310 * 311 * mLock must be held when this function is called. 312 * 313 * @param processName the process name of the client 314 */ 315 virtual std::optional<HalClientId> createClientIdLocked( 316 const std::string &processName); 317 318 /** 319 * Returns true if @p clientId and @p transactionId match the 320 * corresponding values in @p transaction. 321 * 322 * mLock must be held when this function is called. 323 */ isPendingTransactionMatchedLocked(HalClientId clientId,uint32_t transactionId,const std::optional<PendingTransaction> & transaction)324 static bool isPendingTransactionMatchedLocked( 325 HalClientId clientId, uint32_t transactionId, 326 const std::optional<PendingTransaction> &transaction) { 327 return transaction.has_value() && transaction->clientId == clientId && 328 transaction->transactionId == transactionId; 329 } 330 331 /** 332 * Returns true if the load transaction is expected. 333 * 334 * mLock must be held when this function is called. 335 */ 336 bool isPendingLoadTransactionMatchedLocked(HalClientId clientId, 337 uint32_t transactionId, 338 uint32_t currentFragmentId); 339 340 /** 341 * Checks if the transaction registration is allowed and clears out any stale 342 * pending transaction if possible. 343 * 344 * This function is called when registering a new transaction. The reason that 345 * we still proceed when there is already a pending transaction is because we 346 * don't want a stale one, for whatever reason, to block future transactions. 347 * However, every transaction is guaranteed to have up to 348 * kTransactionTimeoutThresholdMs to finish. 349 * 350 * mLock must be held when this function is called. 351 * 352 * @param clientId id of the client trying to register the transaction 353 * 354 * @return true if registration is allowed, otherwise false. 355 */ 356 bool isNewTransactionAllowedLocked(HalClientId clientId); 357 358 /** 359 * Returns true if the clientId is being used. 360 * 361 * mLock must be held when this function is called. 362 */ isAllocatedClientIdLocked(HalClientId clientId)363 inline bool isAllocatedClientIdLocked(HalClientId clientId) { 364 return mClientIdsToClientInfo.find(clientId) != 365 mClientIdsToClientInfo.end(); 366 } 367 368 /** 369 * Returns true if the pid is being used to identify a client. 370 * 371 * mLock must be held when this function is called. 372 */ isKnownPIdLocked(pid_t pid)373 inline bool isKnownPIdLocked(pid_t pid) { 374 return mPIdsToClientIds.find(pid) != mPIdsToClientIds.end(); 375 } 376 377 /** Returns true if the endpoint id is within the accepted range. */ isValidEndpointId(const HalClientId & clientId,const HostEndpointId & endpointId)378 [[nodiscard]] inline bool isValidEndpointId( 379 const HalClientId &clientId, const HostEndpointId &endpointId) const { 380 if (clientId != mFrameworkServiceClientId) { 381 return endpointId <= kMaxVendorEndpointId; 382 } 383 return true; 384 } 385 386 /** 387 * Overrides the old callback registered with the client. 388 * 389 * @return true if success, otherwise false 390 */ 391 bool overrideCallbackLocked( 392 pid_t pid, const std::shared_ptr<IContextHubCallback> &callback, 393 const ndk::ScopedAIBinder_DeathRecipient &deathRecipient, 394 void *deathRecipientCookie); 395 396 /** 397 * Extracts the client id from the endpoint id. 398 * 399 * @param endpointId the endpoint id received from CHRE, before any conversion 400 */ getClientIdFromEndpointId(const HostEndpointId & endpointId)401 [[nodiscard]] inline HalClientId getClientIdFromEndpointId( 402 const HostEndpointId &endpointId) const { 403 if (endpointId & kVendorEndpointIdBitMask) { 404 return endpointId >> kNumOfBitsForEndpointId & kMaxHalClientId; 405 } 406 return mFrameworkServiceClientId; 407 } 408 getProcessName(pid_t)409 std::string getProcessName(pid_t /*pid*/) { 410 // TODO(b/274597758): this is a temporary solution that should be updated 411 // after b/274597758 is resolved. 412 if (mIsFirstClient) { 413 mIsFirstClient = false; 414 return kSystemServerName; 415 } 416 return "the_vendor_client"; 417 } 418 419 bool mIsFirstClient = true; 420 421 // next available client id 422 HalClientId mNextClientId = kDefaultHalClientId + 1; 423 // framework service client id 424 HalClientId mFrameworkServiceClientId = kDefaultHalClientId; 425 426 // The lock guarding the access to clients' states and pending transactions 427 std::mutex mLock; 428 429 // Map from process name to client id which stays consistent with the file 430 // stored at kClientMappingFilePath 431 std::unordered_map<std::string, HalClientId> mProcessNamesToClientIds{}; 432 // Map from pids to client ids 433 std::unordered_map<pid_t, HalClientId> mPIdsToClientIds{}; 434 // Map from client ids to ClientInfos 435 std::unordered_map<HalClientId, HalClientInfo> mClientIdsToClientInfo{}; 436 437 // States tracking pending transactions 438 std::optional<PendingLoadTransaction> mPendingLoadTransaction = std::nullopt; 439 std::optional<PendingTransaction> mPendingUnloadTransaction = std::nullopt; 440 }; 441 } // namespace android::hardware::contexthub::common::implementation 442 443 #endif // ANDROID_HARDWARE_CONTEXTHUB_COMMON_HAL_CLIENT_MANAGER_H_ 444