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 #include "hal_client_manager.h"
17
18 #include <cstdio>
19 #include <fstream>
20
21 #include <aidl/android/hardware/contexthub/AsyncEventType.h>
22 #include <android-base/strings.h>
23 #include <json/json.h>
24 #include <utils/SystemClock.h>
25
26 namespace android::hardware::contexthub::common::implementation {
27
28 using ::aidl::android::hardware::contexthub::AsyncEventType;
29 using ::aidl::android::hardware::contexthub::ContextHubMessage;
30 using ::aidl::android::hardware::contexthub::HostEndpointInfo;
31 using ::aidl::android::hardware::contexthub::IContextHubCallback;
32
33 namespace {
34 using Client = HalClientManager::Client;
getClientMappingsFromFile(const std::string & filePath,Json::Value & mappings)35 bool getClientMappingsFromFile(const std::string &filePath,
36 Json::Value &mappings) {
37 std::fstream file(filePath);
38 Json::CharReaderBuilder builder;
39 return file.good() &&
40 Json::parseFromStream(builder, file, &mappings, /* errs= */ nullptr);
41 }
42
isCallbackV3Enabled(const std::shared_ptr<IContextHubCallback> & callback)43 bool isCallbackV3Enabled(const std::shared_ptr<IContextHubCallback> &callback) {
44 int32_t callbackVersion;
45 callback->getInterfaceVersion(&callbackVersion);
46 return callbackVersion >= 3;
47 }
48
getName(const std::shared_ptr<IContextHubCallback> & callback)49 std::string getName(const std::shared_ptr<IContextHubCallback> &callback) {
50 if (!isCallbackV3Enabled(callback)) {
51 return std::string{Client::kNameUnset};
52 }
53 std::string name;
54 callback->getName(&name);
55 return name;
56 }
57
mutateVendorEndpointId(const Client & client,HostEndpointId endpointId)58 inline HostEndpointId mutateVendorEndpointId(const Client &client,
59 HostEndpointId endpointId) {
60 return HalClientManager::kVendorEndpointIdBitMask |
61 client.clientId << HalClientManager::kNumOfBitsForEndpointId |
62 endpointId;
63 }
64 } // namespace
65
getUuid(const std::shared_ptr<IContextHubCallback> & callback)66 std::string HalClientManager::getUuid(
67 const std::shared_ptr<IContextHubCallback> &callback) {
68 if (!isCallbackV3Enabled(callback)) {
69 Client *client = getClientByUuid(kSystemServerUuid);
70 bool isSystemServerConnected =
71 client != nullptr && client->pid != Client::kPidUnset;
72 return isSystemServerConnected ? kVendorClientUuid : kSystemServerUuid;
73 }
74
75 std::array<uint8_t, 16> uuidBytes{};
76 callback->getUuid(&uuidBytes);
77 std::ostringstream oStringStream;
78 char buffer[3]{};
79 for (const uint8_t &byte : uuidBytes) {
80 snprintf(buffer, sizeof(buffer), "%02x", static_cast<int>(byte));
81 oStringStream << buffer;
82 }
83 return oStringStream.str();
84 }
85
getClientByField(const std::function<bool (const Client & client)> & fieldMatcher)86 Client *HalClientManager::getClientByField(
87 const std::function<bool(const Client &client)> &fieldMatcher) {
88 for (Client &client : mClients) {
89 if (fieldMatcher(client)) {
90 return &client;
91 }
92 }
93 return nullptr;
94 }
95
getClientByClientId(HalClientId clientId)96 Client *HalClientManager::getClientByClientId(HalClientId clientId) {
97 return getClientByField([&clientId](const Client &client) {
98 return client.clientId == clientId;
99 });
100 }
101
getClientByUuid(const std::string & uuid)102 Client *HalClientManager::getClientByUuid(const std::string &uuid) {
103 return getClientByField(
104 [&uuid](const Client &client) { return client.uuid == uuid; });
105 }
106
getClientByProcessId(pid_t pid)107 Client *HalClientManager::getClientByProcessId(pid_t pid) {
108 return getClientByField(
109 [&pid](const Client &client) { return client.pid == pid; });
110 }
111
updateNextClientId()112 bool HalClientManager::updateNextClientId() {
113 std::unordered_set<HalClientId> usedClientIds{};
114 for (const Client &client : mClients) {
115 usedClientIds.insert(client.clientId);
116 }
117 for (int i = 0; i < kMaxNumOfHalClients; i++) {
118 mNextClientId = (mNextClientId + 1) % kMaxHalClientId;
119 if (mNextClientId != ::chre::kHostClientIdUnspecified &&
120 mReservedClientIds.find(mNextClientId) == mReservedClientIds.end() &&
121 usedClientIds.find(mNextClientId) == usedClientIds.end()) {
122 // Found a client id that is not reserved nor used.
123 return true;
124 }
125 }
126 LOGE("Unable to find the next available client id");
127 mNextClientId = ::chre::kHostClientIdUnspecified;
128 return false;
129 }
130
createClient(const std::string & uuid,pid_t pid,const std::shared_ptr<IContextHubCallback> & callback,void * deathRecipientCookie)131 bool HalClientManager::createClient(
132 const std::string &uuid, pid_t pid,
133 const std::shared_ptr<IContextHubCallback> &callback,
134 void *deathRecipientCookie) {
135 if (mClients.size() > kMaxNumOfHalClients ||
136 mNextClientId == ::chre::kHostClientIdUnspecified) {
137 LOGE("Too many HAL clients (%zu) registered which should never happen.",
138 mClients.size());
139 return false;
140 }
141 mClients.emplace_back(uuid, getName(callback), mNextClientId, pid, callback,
142 deathRecipientCookie);
143 updateClientIdMappingFile();
144 updateNextClientId();
145 return true;
146 }
147
getClientId(pid_t pid)148 HalClientId HalClientManager::getClientId(pid_t pid) {
149 const std::lock_guard<std::mutex> lock(mLock);
150 const Client *client = getClientByProcessId(pid);
151 if (client == nullptr) {
152 LOGE("Failed to find the client id for pid %d", pid);
153 return ::chre::kHostClientIdUnspecified;
154 }
155 return client->clientId;
156 }
157
getCallback(HalClientId clientId)158 std::shared_ptr<IContextHubCallback> HalClientManager::getCallback(
159 HalClientId clientId) {
160 const std::lock_guard<std::mutex> lock(mLock);
161 const Client *client = getClientByClientId(clientId);
162 if (client == nullptr) {
163 LOGE("Failed to find the callback for the client id %" PRIu16, clientId);
164 return nullptr;
165 }
166 return client->callback;
167 }
168
registerCallback(pid_t pid,const std::shared_ptr<IContextHubCallback> & callback,void * deathRecipientCookie)169 bool HalClientManager::registerCallback(
170 pid_t pid, const std::shared_ptr<IContextHubCallback> &callback,
171 void *deathRecipientCookie) {
172 const std::lock_guard<std::mutex> lock(mLock);
173 Client *client = getClientByProcessId(pid);
174 if (client != nullptr) {
175 LOGW("The pid %d has already registered. Overriding its callback.", pid);
176 if (!mDeadClientUnlinker(client->callback, client->deathRecipientCookie)) {
177 LOGE("Unable to unlink the old callback for pid %d", pid);
178 return false;
179 }
180 client->callback.reset();
181 client->callback = callback;
182 client->deathRecipientCookie = deathRecipientCookie;
183 return true;
184 }
185
186 std::string uuid = getUuid(callback);
187 client = getClientByUuid(uuid);
188 if (client != nullptr) {
189 if (client->pid != Client::kPidUnset) {
190 // A client is trying to connect to HAL from a different process. But the
191 // previous connection is still active because otherwise the pid will be
192 // cleared in handleClientDeath().
193 LOGE("Client (uuid=%s, name=%s) already has a connection to HAL.",
194 uuid.c_str(), client->name.c_str());
195 return false;
196 }
197
198 // For a known client the previous assigned clientId will be reused.
199 client->reset(/* processId= */ pid,
200 /* contextHubCallback= */ callback,
201 /* cookie= */ deathRecipientCookie);
202
203 // Updates a client's name only if it is changed from Client::NAME_UNSET.
204 std::string name = getName(callback);
205 if (client->name == Client::kNameUnset && name != Client::kNameUnset) {
206 client->name = name;
207 updateClientIdMappingFile();
208 }
209 return true;
210 }
211 return createClient(uuid, pid, callback, deathRecipientCookie);
212 }
213
handleClientDeath(pid_t pid)214 void HalClientManager::handleClientDeath(pid_t pid) {
215 const std::lock_guard<std::mutex> lock(mLock);
216 Client *client = getClientByProcessId(pid);
217 if (client == nullptr) {
218 LOGE("Failed to locate the dead pid %d", pid);
219 return;
220 }
221
222 if (!mDeadClientUnlinker(client->callback, client->deathRecipientCookie)) {
223 LOGE("Unable to unlink the old callback for pid %d in death handler", pid);
224 }
225 client->reset(/* processId= */ Client::kPidUnset,
226 /* contextHubCallback= */ nullptr, /* cookie= */ nullptr);
227
228 if (mPendingLoadTransaction.has_value() &&
229 mPendingLoadTransaction->clientId == client->clientId) {
230 mPendingLoadTransaction.reset();
231 }
232 if (mPendingUnloadTransaction.has_value() &&
233 mPendingUnloadTransaction->clientId == client->clientId) {
234 mPendingLoadTransaction.reset();
235 }
236 LOGI("Process %" PRIu32 " is disconnected from HAL.", pid);
237 }
238
registerPendingLoadTransaction(pid_t pid,std::unique_ptr<chre::FragmentedLoadTransaction> transaction)239 bool HalClientManager::registerPendingLoadTransaction(
240 pid_t pid, std::unique_ptr<chre::FragmentedLoadTransaction> transaction) {
241 if (transaction->isComplete()) {
242 LOGW("No need to register a completed load transaction.");
243 return false;
244 }
245
246 const std::lock_guard<std::mutex> lock(mLock);
247 const Client *client = getClientByProcessId(pid);
248 if (client == nullptr) {
249 LOGE("Unknown HAL client when registering its pending load transaction.");
250 return false;
251 }
252 if (!isNewTransactionAllowed(client->clientId)) {
253 return false;
254 }
255 mPendingLoadTransaction.emplace(
256 client->clientId, /* registeredTimeMs= */ android::elapsedRealtime(),
257 /* currentFragmentId= */ 0, std::move(transaction));
258 return true;
259 }
260
261 std::optional<chre::FragmentedLoadRequest>
getNextFragmentedLoadRequest()262 HalClientManager::getNextFragmentedLoadRequest() {
263 const std::lock_guard<std::mutex> lock(mLock);
264 if (mPendingLoadTransaction->transaction->isComplete()) {
265 LOGI("Pending load transaction %" PRIu32
266 " is finished with client %" PRIu16,
267 mPendingLoadTransaction->transaction->getTransactionId(),
268 mPendingLoadTransaction->clientId);
269 mPendingLoadTransaction.reset();
270 return std::nullopt;
271 }
272 auto request = mPendingLoadTransaction->transaction->getNextRequest();
273 mPendingLoadTransaction->currentFragmentId = request.fragmentId;
274 LOGV("Client %" PRIu16 " has fragment #%zu ready",
275 mPendingLoadTransaction->clientId, request.fragmentId);
276 return request;
277 }
278
registerPendingUnloadTransaction(pid_t pid,uint32_t transactionId,int64_t nanoappId)279 bool HalClientManager::registerPendingUnloadTransaction(pid_t pid,
280 uint32_t transactionId,
281 int64_t nanoappId) {
282 const std::lock_guard<std::mutex> lock(mLock);
283 const Client *client = getClientByProcessId(pid);
284 if (client == nullptr) {
285 LOGE("Unknown HAL client when registering its pending unload transaction.");
286 return false;
287 }
288 if (!isNewTransactionAllowed(client->clientId)) {
289 return false;
290 }
291 mPendingUnloadTransaction.emplace(
292 client->clientId, transactionId,
293 /* registeredTimeMs= */ android::elapsedRealtime(), nanoappId);
294 return true;
295 }
296
isNewTransactionAllowed(HalClientId clientId)297 bool HalClientManager::isNewTransactionAllowed(HalClientId clientId) {
298 if (mPendingLoadTransaction.has_value()) {
299 auto timeElapsedMs =
300 android::elapsedRealtime() - mPendingLoadTransaction->registeredTimeMs;
301 if (timeElapsedMs < kTransactionTimeoutThresholdMs) {
302 LOGE("Rejects client %" PRIu16
303 "'s transaction because an active load "
304 "transaction %" PRIu32 " with current fragment id %" PRIu32
305 " from client %" PRIu16 " exists. Try again later.",
306 clientId, mPendingLoadTransaction->transaction->getTransactionId(),
307 mPendingLoadTransaction->currentFragmentId,
308 mPendingLoadTransaction->clientId);
309 return false;
310 }
311 LOGE("Client %" PRIu16 "'s pending load transaction %" PRIu32
312 " with current fragment id %" PRIu32
313 " is overridden by client %" PRIu16
314 " after holding the slot for %" PRIu64 " ms",
315 mPendingLoadTransaction->clientId,
316 mPendingLoadTransaction->transaction->getTransactionId(),
317 mPendingLoadTransaction->currentFragmentId, clientId, timeElapsedMs);
318 mPendingLoadTransaction.reset();
319 return true;
320 }
321 if (mPendingUnloadTransaction.has_value()) {
322 auto timeElapsedMs = android::elapsedRealtime() -
323 mPendingUnloadTransaction->registeredTimeMs;
324 if (timeElapsedMs < kTransactionTimeoutThresholdMs) {
325 LOGE("Rejects client %" PRIu16
326 "'s transaction because an active unload "
327 "transaction %" PRIu32 " from client %" PRIu16
328 " exists. Try again later.",
329 clientId, mPendingUnloadTransaction->transactionId,
330 mPendingUnloadTransaction->clientId);
331 return false;
332 }
333 LOGE("A pending unload transaction %" PRIu32
334 " registered by client %" PRIu16
335 " is overridden by a new transaction from client %" PRIu16
336 " after holding the slot for %" PRIu64 "ms",
337 mPendingUnloadTransaction->transactionId,
338 mPendingUnloadTransaction->clientId, clientId, timeElapsedMs);
339 mPendingUnloadTransaction.reset();
340 return true;
341 }
342 return true;
343 }
344
registerEndpointId(pid_t pid,const HostEndpointId & endpointId)345 bool HalClientManager::registerEndpointId(pid_t pid,
346 const HostEndpointId &endpointId) {
347 const std::lock_guard<std::mutex> lock(mLock);
348 Client *client = getClientByProcessId(pid);
349 if (client == nullptr) {
350 LOGE(
351 "Unknown HAL client (pid %d). Register the callback before registering "
352 "an endpoint.",
353 pid);
354 return false;
355 }
356 if (!isValidEndpointId(client, endpointId)) {
357 LOGE("Endpoint id %" PRIu16 " from process %d is out of range.", endpointId,
358 pid);
359 return false;
360 }
361 if (client->endpointIds.find(endpointId) != client->endpointIds.end()) {
362 LOGW("Client %" PRIu16 "'s endpoint id %" PRIu16 " is already registered",
363 endpointId, client->clientId);
364 } else {
365 client->endpointIds.insert(endpointId);
366 LOGI("Client %" PRIu16 " registers endpoint id %" PRIu16, client->clientId,
367 endpointId);
368 }
369 return true;
370 }
371
removeEndpointId(pid_t pid,const HostEndpointId & endpointId)372 bool HalClientManager::removeEndpointId(pid_t pid,
373 const HostEndpointId &endpointId) {
374 const std::lock_guard<std::mutex> lock(mLock);
375 Client *client = getClientByProcessId(pid);
376 if (client == nullptr) {
377 LOGE(
378 "Unknown HAL client (pid %d). A callback should have been registered "
379 "before removing an endpoint.",
380 pid);
381 return false;
382 }
383 if (!isValidEndpointId(client, endpointId)) {
384 LOGE("Endpoint id %" PRIu16 " from process %d is out of range.", endpointId,
385 pid);
386 return false;
387 }
388 if (client->endpointIds.find(endpointId) == client->endpointIds.end()) {
389 LOGW("The endpoint %" PRIu16 " is not connected.", endpointId);
390 return false;
391 }
392 client->endpointIds.erase(endpointId);
393 LOGI("Endpoint id %" PRIu16 " is removed from client %" PRIu16, endpointId,
394 client->clientId);
395 return true;
396 }
397
getCallbackForEndpoint(const HostEndpointId mutatedEndpointId)398 std::shared_ptr<IContextHubCallback> HalClientManager::getCallbackForEndpoint(
399 const HostEndpointId mutatedEndpointId) {
400 const std::lock_guard<std::mutex> lock(mLock);
401 Client *client;
402 if (mutatedEndpointId & kVendorEndpointIdBitMask) {
403 HalClientId clientId =
404 mutatedEndpointId >> kNumOfBitsForEndpointId & kMaxHalClientId;
405 client = getClientByClientId(clientId);
406 } else {
407 client = getClientByUuid(kSystemServerUuid);
408 }
409
410 HostEndpointId originalEndpointId =
411 convertToOriginalEndpointId(mutatedEndpointId);
412 if (client == nullptr) {
413 LOGE("Unknown endpoint id %" PRIu16 ". Please register the callback first.",
414 originalEndpointId);
415 return nullptr;
416 }
417 if (client->endpointIds.find(originalEndpointId) ==
418 client->endpointIds.end()) {
419 LOGW(
420 "Received a message from CHRE for an unknown or disconnected endpoint "
421 "id %" PRIu16,
422 originalEndpointId);
423 }
424 return client->callback;
425 }
426
sendMessageForAllCallbacks(const ContextHubMessage & message,const std::vector<std::string> & messageParams)427 void HalClientManager::sendMessageForAllCallbacks(
428 const ContextHubMessage &message,
429 const std::vector<std::string> &messageParams) {
430 const std::lock_guard<std::mutex> lock(mLock);
431 for (const auto &client : mClients) {
432 if (client.callback != nullptr) {
433 client.callback->handleContextHubMessage(message, messageParams);
434 }
435 }
436 }
437
438 const std::unordered_set<HostEndpointId>
getAllConnectedEndpoints(pid_t pid)439 *HalClientManager::getAllConnectedEndpoints(pid_t pid) {
440 const std::lock_guard<std::mutex> lock(mLock);
441 const Client *client = getClientByProcessId(pid);
442 if (client == nullptr) {
443 LOGE("Unknown HAL client with pid %d", pid);
444 return nullptr;
445 }
446 return &(client->endpointIds);
447 }
448
mutateEndpointIdFromHostIfNeeded(pid_t pid,HostEndpointId & endpointId)449 bool HalClientManager::mutateEndpointIdFromHostIfNeeded(
450 pid_t pid, HostEndpointId &endpointId) {
451 const std::lock_guard<std::mutex> lock(mLock);
452 const Client *client = getClientByProcessId(pid);
453 if (client == nullptr) {
454 LOGE("Unknown HAL client with pid %d", pid);
455 return false;
456 }
457
458 // no need to mutate client id for framework service
459 if (client->uuid != kSystemServerUuid) {
460 endpointId = mutateVendorEndpointId(*client, endpointId);
461 }
462 return true;
463 }
464
convertToOriginalEndpointId(const HostEndpointId & endpointId)465 HostEndpointId HalClientManager::convertToOriginalEndpointId(
466 const HostEndpointId &endpointId) {
467 if (endpointId & kVendorEndpointIdBitMask) {
468 return endpointId & kMaxVendorEndpointId;
469 }
470 return endpointId;
471 }
472
HalClientManager(DeadClientUnlinker deadClientUnlinker,const std::string & clientIdMappingFilePath,const std::unordered_set<HalClientId> & reservedClientIds)473 HalClientManager::HalClientManager(
474 DeadClientUnlinker deadClientUnlinker,
475 const std::string &clientIdMappingFilePath,
476 const std::unordered_set<HalClientId> &reservedClientIds) {
477 mDeadClientUnlinker = std::move(deadClientUnlinker);
478 mClientMappingFilePath = clientIdMappingFilePath;
479 mReservedClientIds = reservedClientIds;
480 // Parses the file to construct a mapping from process names to client ids.
481 Json::Value mappings;
482 if (!getClientMappingsFromFile(mClientMappingFilePath, mappings)) {
483 // TODO(b/247124878): When the device was firstly booted up the file doesn't
484 // exist which is expected. Consider to create a default file to avoid
485 // confusions.
486 LOGW("Unable to find and read %s.", mClientMappingFilePath.c_str());
487 } else {
488 for (int i = 0; i < mappings.size(); i++) {
489 Json::Value mapping = mappings[i];
490 if (!mapping.isMember(kJsonClientId) || !mapping.isMember(kJsonUuid) ||
491 !mapping.isMember(kJsonName)) {
492 LOGE("Unable to find expected key name for the entry %d", i);
493 continue;
494 }
495 std::string uuid = mapping[kJsonUuid].asString();
496 std::string name = mapping[kJsonName].asString();
497 auto clientId = static_cast<HalClientId>(mapping[kJsonClientId].asUInt());
498 mClients.emplace_back(uuid, name, clientId);
499 }
500 }
501 std::lock_guard<std::mutex> lock{mLock};
502 updateNextClientId();
503 }
504
505 std::optional<HalClientManager::PendingLoadNanoappInfo>
getNanoappInfoFromPendingLoadTransaction(HalClientId clientId,uint32_t transactionId,uint32_t currentFragmentId)506 HalClientManager::getNanoappInfoFromPendingLoadTransaction(
507 HalClientId clientId, uint32_t transactionId, uint32_t currentFragmentId) {
508 const std::lock_guard<std::mutex> lock(mLock);
509 bool success =
510 isPendingTransactionMatched(clientId, transactionId,
511 mPendingLoadTransaction) &&
512 mPendingLoadTransaction->currentFragmentId == currentFragmentId;
513 if (!success) {
514 if (mPendingLoadTransaction.has_value()) {
515 LOGE("Transaction of client %" PRIu16 " transaction %" PRIu32
516 " fragment %" PRIu32
517 " doesn't match the current pending transaction (client %" PRIu16
518 " transaction %" PRIu32 " fragment %" PRIu32 ").",
519 clientId, transactionId, currentFragmentId,
520 mPendingLoadTransaction->clientId,
521 mPendingLoadTransaction->transactionId,
522 mPendingLoadTransaction->currentFragmentId);
523 } else {
524 LOGE("Transaction of client %" PRIu16 " transaction %" PRIu32
525 " fragment %" PRIu32 " doesn't match any pending transaction.",
526 clientId, transactionId, currentFragmentId);
527 }
528 return std::nullopt;
529 }
530 return std::make_optional<PendingLoadNanoappInfo>(
531 mPendingLoadTransaction->getNanoappInfo());
532 }
533
resetPendingLoadTransaction()534 void HalClientManager::resetPendingLoadTransaction() {
535 const std::lock_guard<std::mutex> lock(mLock);
536 mPendingLoadTransaction.reset();
537 }
538
resetPendingUnloadTransaction(HalClientId clientId,uint32_t transactionId)539 std::optional<int64_t> HalClientManager::resetPendingUnloadTransaction(
540 HalClientId clientId, uint32_t transactionId) {
541 const std::lock_guard<std::mutex> lock(mLock);
542 // Only clear a pending transaction when the client id and the transaction id
543 // are both matched
544 if (isPendingTransactionMatched(clientId, transactionId,
545 mPendingUnloadTransaction)) {
546 int64_t nanoappId = mPendingUnloadTransaction->nanoappId;
547 LOGI("Clears out the pending unload transaction for nanoapp 0x%" PRIx64
548 ": client id %" PRIu16 ", transaction id %" PRIu32,
549 nanoappId, clientId, transactionId);
550 mPendingUnloadTransaction.reset();
551 return nanoappId;
552 }
553 LOGW("Client %" PRIu16 " doesn't have a pending unload transaction %" PRIu32
554 ". Skip resetting",
555 clientId, transactionId);
556 return std::nullopt;
557 }
558
handleChreRestart()559 void HalClientManager::handleChreRestart() {
560 std::vector<std::shared_ptr<IContextHubCallback>> callbacks;
561 {
562 const std::lock_guard<std::mutex> lock(mLock);
563 mPendingLoadTransaction.reset();
564 mPendingUnloadTransaction.reset();
565 for (Client &client : mClients) {
566 client.endpointIds.clear();
567 if (client.callback != nullptr) {
568 // Create a copy of the callback and call it later without holding the
569 // lock to avoid deadlocks.
570 callbacks.push_back(client.callback);
571 }
572 }
573 }
574
575 for (const auto &callback : callbacks) {
576 callback->handleContextHubAsyncEvent(AsyncEventType::RESTARTED);
577 }
578 }
579
updateClientIdMappingFile()580 void HalClientManager::updateClientIdMappingFile() {
581 Json::Value mappings;
582 for (const auto &client : mClients) {
583 Json::Value mapping;
584 mapping[kJsonUuid] = client.uuid;
585 mapping[kJsonName] = client.name;
586 mapping[kJsonClientId] = client.clientId;
587 mappings.append(mapping);
588 }
589 // write to the file; Create the file if it doesn't exist
590 Json::StreamWriterBuilder factory;
591 std::unique_ptr<Json::StreamWriter> const writer(factory.newStreamWriter());
592 std::ofstream fileStream(mClientMappingFilePath);
593 writer->write(mappings, &fileStream);
594 fileStream << std::endl;
595 }
596
debugDump()597 std::string HalClientManager::debugDump() {
598 std::ostringstream result;
599 result << "\nKnown clients:\n"
600 << "Format: [isConnected] (uuid : name) : Pid, ClientId, "
601 "{endpointIds, in 'original (mutated)' format, sorted}\n";
602
603 // Dump states of each client.
604 const std::lock_guard<std::mutex> lock(mLock);
605
606 std::vector<HostEndpointId> endpointIds;
607 for (const auto &client : mClients) {
608 for (const HostEndpointId &endpointId : client.endpointIds) {
609 endpointIds.push_back(endpointId);
610 }
611 std::sort(endpointIds.begin(), endpointIds.end());
612 std::ostringstream endpointIdsStream;
613 for (const HostEndpointId &endpointId : endpointIds) {
614 endpointIdsStream << endpointId;
615 // Only vendor endpoint ids are mutated.
616 if (client.uuid != kSystemServerUuid) {
617 endpointIdsStream << " (0x" << std::hex
618 << mutateVendorEndpointId(client, endpointId) << ")";
619 }
620 endpointIdsStream << ", ";
621 }
622 bool isConnected = client.callback != nullptr;
623 result << (isConnected ? "[ x ]" : "[ ]") << " (" << std::setw(32)
624 << client.uuid << " : " << std::setw(17) << client.name
625 << ") : " << std::setw(5) << client.pid << ", " << std::setw(2)
626 << client.clientId << ", {" << endpointIdsStream.str() << "}\n";
627 endpointIds.clear();
628 }
629
630 // Dump active transactions, if any.
631 result << "\nActive pending transaction:\n";
632 if (mPendingLoadTransaction.has_value()) {
633 result << "Load transaction from client "
634 << mPendingLoadTransaction->clientId << ": Transaction "
635 << mPendingLoadTransaction->transactionId
636 << " with current fragment id "
637 << mPendingLoadTransaction->currentFragmentId << "\n";
638 }
639 if (mPendingUnloadTransaction.has_value()) {
640 result << "Unload transaction from client "
641 << mPendingUnloadTransaction->clientId << ": Transaction "
642 << mPendingUnloadTransaction->transactionId << "\n";
643 }
644
645 return result.str();
646 }
647 } // namespace android::hardware::contexthub::common::implementation
648