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