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 #include "message_hub_manager.h"
18
19 #include <inttypes.h>
20 #include <unistd.h>
21
22 #include <cstdint>
23 #include <functional>
24 #include <list>
25 #include <memory>
26 #include <optional>
27 #include <string>
28 #include <unordered_map>
29 #include <utility>
30 #include <vector>
31
32 #include <aidl/android/hardware/contexthub/BnContextHub.h>
33 #include <android-base/thread_annotations.h>
34
35 #include "chre_host/log.h"
36 #include "pw_result/result.h"
37 #include "pw_status/status.h"
38 #include "pw_status/try.h"
39
40 namespace android::hardware::contexthub::common::implementation {
41
42 using ::aidl::android::hardware::contexthub::Reason;
43
44 using HostHub = MessageHubManager::HostHub;
45
HostHub(MessageHubManager & manager,std::shared_ptr<IEndpointCallback> callback,const HubInfo & info)46 HostHub::HostHub(MessageHubManager &manager,
47 std::shared_ptr<IEndpointCallback> callback,
48 const HubInfo &info)
49 : mManager(manager), kInfo(info) {
50 auto *cookie = new DeathRecipientCookie{&mManager, kInfo.hubId};
51 if (!manager.mDeathRecipient->linkCallback(callback, cookie).ok()) {
52 LOGE("Failed to link callback for hub %" PRId64 " to death recipient",
53 kInfo.hubId);
54 delete cookie;
55 return;
56 }
57 mCookie = cookie;
58 mCallback = std::move(callback);
59 }
60
addEndpoint(const EndpointInfo & info)61 pw::Status HostHub::addEndpoint(const EndpointInfo &info) {
62 std::lock_guard lock(mManager.mLock);
63 PW_TRY(checkValidLocked());
64 if (info.id.hubId != kInfo.hubId) {
65 LOGE("Hub %" PRId64 " registering endpoint for different hub %" PRId64,
66 kInfo.hubId, info.id.hubId);
67 return pw::Status::PermissionDenied();
68 }
69 int64_t id = info.id.id;
70 if (auto it = mIdToEndpoint.find(id); it != mIdToEndpoint.end()) {
71 LOGE("Endpoint %" PRId64 " already exists in hub %" PRId64, id,
72 kInfo.hubId);
73 return pw::Status::AlreadyExists();
74 }
75 mIdToEndpoint.insert({id, info});
76 return pw::OkStatus();
77 }
78
removeEndpoint(const EndpointId & id)79 pw::Result<std::vector<uint16_t>> HostHub::removeEndpoint(
80 const EndpointId &id) {
81 std::lock_guard lock(mManager.mLock);
82 PW_TRY(checkValidLocked());
83 if (auto it = mIdToEndpoint.find(id.id); it != mIdToEndpoint.end()) {
84 std::vector<uint16_t> sessions;
85 for (const auto &[sessionId, session] : mIdToSession) {
86 if (session.mHostEndpoint == id) sessions.push_back(sessionId);
87 }
88 for (auto sessionId : sessions) mIdToSession.erase(sessionId);
89 mIdToEndpoint.erase(it);
90 return sessions;
91 }
92 LOGE("Hub %" PRId64 " tried to remove unknown endpoint %" PRId64, kInfo.hubId,
93 id.id);
94 return pw::Status::NotFound();
95 }
96
reserveSessionIdRange(uint16_t size)97 pw::Result<std::pair<uint16_t, uint16_t>> HostHub::reserveSessionIdRange(
98 uint16_t size) {
99 std::lock_guard lock(mManager.mLock);
100 PW_TRY(checkValidLocked());
101 if (!size || size > kSessionIdMaxRange) {
102 LOGE("Hub %" PRId64 " tried to allocate %" PRIu16 " session ids",
103 kInfo.hubId, size);
104 return pw::Status::InvalidArgument();
105 }
106 if (mManager.mNextSessionId < kHostSessionIdBase ||
107 USHRT_MAX - mManager.mNextSessionId + 1 < size) {
108 LOGW("Could not allocate %" PRIu16 " session ids, ids exhausted", size);
109 return pw::Status::ResourceExhausted();
110 }
111 mSessionIdRanges.push_back(
112 {mManager.mNextSessionId, mManager.mNextSessionId + size - 1});
113 mManager.mNextSessionId += size;
114 return mSessionIdRanges.back();
115 }
116
openSession(const EndpointId & hostEndpoint,const EndpointId & embeddedEndpoint,uint16_t sessionId,std::optional<std::string> serviceDescriptor,bool hostInitiated)117 pw::Status HostHub::openSession(const EndpointId &hostEndpoint,
118 const EndpointId &embeddedEndpoint,
119 uint16_t sessionId,
120 std::optional<std::string> serviceDescriptor,
121 bool hostInitiated) {
122 std::lock_guard lock(mManager.mLock);
123 PW_TRY(checkValidLocked());
124
125 // Lookup the endpoints.
126 PW_TRY(endpointExistsLocked(
127 hostEndpoint, hostInitiated ? std::nullopt : serviceDescriptor));
128 PW_TRY(mManager.embeddedEndpointExistsLocked(
129 embeddedEndpoint, hostInitiated ? serviceDescriptor : std::nullopt));
130
131 // Validate the session id.
132 if (hostInitiated) {
133 if (!sessionIdInRangeLocked(sessionId)) {
134 LOGE("Session id %" PRIu16 " out of range for hub %" PRId64, sessionId,
135 kInfo.hubId);
136 return pw::Status::OutOfRange();
137 }
138 } else if (sessionId >= kHostSessionIdBase) {
139 LOGE("Remote endpoint (%" PRId64 ", %" PRId64
140 ") attempting to start "
141 "session with invalid id %" PRIu16,
142 embeddedEndpoint.hubId, embeddedEndpoint.id, sessionId);
143 return pw::Status::InvalidArgument();
144 }
145
146 // Prune a stale session with this id if present.
147 if (auto it = mIdToSession.find(sessionId); it != mIdToSession.end()) {
148 Session &session = it->second;
149 // If the session is in a valid state, prune it if it was not host
150 // initiated and is pending a final ack from message router.
151 if (!hostInitiated && !session.mPendingDestination &&
152 session.mPendingMessageRouter) {
153 mCallback->onCloseEndpointSession(sessionId, Reason::UNSPECIFIED);
154 LOGD("Pruned session %" PRIu16, sessionId);
155 } else if (hostInitiated && session.mHostEndpoint == hostEndpoint) {
156 LOGE("Hub %" PRId64 " trying to override its own session %" PRIu16,
157 kInfo.hubId, sessionId);
158 return pw::Status::InvalidArgument();
159 } else {
160 LOGE("(host? %" PRId32 ") trying to override session id %" PRIu16
161 ", hub %" PRId64,
162 hostInitiated, sessionId, kInfo.hubId);
163 return pw::Status::AlreadyExists();
164 }
165 mIdToSession.erase(it);
166 }
167
168 // Create and map the new session.
169 mIdToSession.emplace(
170 std::piecewise_construct, std::forward_as_tuple(sessionId),
171 std::forward_as_tuple(hostEndpoint, embeddedEndpoint, hostInitiated));
172
173 // Pass a request from a embedded endpoint to the host endpoint.
174 if (!hostInitiated) {
175 mCallback->onEndpointSessionOpenRequest(sessionId, hostEndpoint,
176 embeddedEndpoint,
177 std::move(serviceDescriptor));
178 }
179 return pw::OkStatus();
180 }
181
closeSession(uint16_t id,std::optional<Reason> reason)182 pw::Status HostHub::closeSession(uint16_t id, std::optional<Reason> reason) {
183 std::lock_guard lock(mManager.mLock);
184 PW_TRY(checkValidLocked());
185 auto it = mIdToSession.find(id);
186 if (it == mIdToSession.end()) {
187 LOGE("Closing unopened session %" PRIu16, id);
188 return pw::Status::NotFound();
189 }
190 mIdToSession.erase(it);
191 if (reason) mCallback->onCloseEndpointSession(id, *reason);
192 return pw::OkStatus();
193 }
194
checkSessionOpen(uint16_t id)195 pw::Status HostHub::checkSessionOpen(uint16_t id) {
196 std::lock_guard lock(mManager.mLock);
197 PW_TRY(checkValidLocked());
198 return checkSessionOpenLocked(id);
199 }
200
ackSession(uint16_t id,bool hostAcked)201 pw::Status HostHub::ackSession(uint16_t id, bool hostAcked) {
202 std::lock_guard lock(mManager.mLock);
203 PW_TRY(checkValidLocked());
204 PW_TRY_ASSIGN(Session * session, getSessionLocked(id));
205 bool isHostSession = id >= kHostSessionIdBase;
206 if (session->mPendingDestination) {
207 if (isHostSession == hostAcked) {
208 LOGE("Session %" PRIu16 " must be acked by other side (host? %" PRId32
209 ")",
210 id, !hostAcked);
211 return pw::Status::PermissionDenied();
212 }
213 session->mPendingDestination = false;
214 // Notify the initiator that the session has been opened.
215 if (isHostSession) mCallback->onEndpointSessionOpenComplete(id);
216 } else if (session->mPendingMessageRouter) {
217 if (hostAcked) {
218 LOGE("Message router must ack session %" PRIu16, id);
219 return pw::Status::PermissionDenied();
220 }
221 session->mPendingMessageRouter = false;
222 } else {
223 LOGE("Received unexpected ack on session %" PRIu16 ", host: %" PRId32, id,
224 hostAcked);
225 }
226 return pw::OkStatus();
227 }
228
handleMessage(uint16_t sessionId,const Message & message)229 pw::Status HostHub::handleMessage(uint16_t sessionId, const Message &message) {
230 std::lock_guard lock(mManager.mLock);
231 PW_TRY(checkValidLocked());
232 PW_TRY(checkSessionOpenLocked(sessionId));
233 mCallback->onMessageReceived(sessionId, message);
234 return pw::OkStatus();
235 }
236
handleMessageDeliveryStatus(uint16_t sessionId,const MessageDeliveryStatus & status)237 pw::Status HostHub::handleMessageDeliveryStatus(
238 uint16_t sessionId, const MessageDeliveryStatus &status) {
239 std::lock_guard lock(mManager.mLock);
240 PW_TRY(checkValidLocked());
241 PW_TRY(checkSessionOpenLocked(sessionId));
242 mCallback->onMessageDeliveryStatusReceived(sessionId, status);
243 return pw::OkStatus();
244 }
245
unregister()246 pw::Status HostHub::unregister() {
247 // If unlinkFromManager() fails, onClientDeath() was already called for this
248 // and we do not need to unlink the death recipient.
249 PW_TRY(unlinkFromManager());
250 if (!mManager.mDeathRecipient->unlinkCallback(mCallback, mCookie).ok()) {
251 LOGW("Process hosting hub %" PRId64 " died simultaneously with unregister",
252 kInfo.hubId);
253 }
254 return pw::OkStatus();
255 }
256
getEndpoints() const257 std::vector<EndpointInfo> HostHub::getEndpoints() const {
258 std::vector<EndpointInfo> endpoints;
259 std::lock_guard lock(mManager.mLock);
260 for (const auto &[id, endpoint] : mIdToEndpoint)
261 endpoints.push_back(endpoint);
262 return endpoints;
263 }
264
unlinkFromManager()265 pw::Status HostHub::unlinkFromManager() {
266 std::lock_guard lock(mManager.mLock);
267 PW_TRY(checkValidLocked()); // returns early if already unlinked
268 // TODO(b/378545373): Release the session id range.
269 mManager.mIdToHostHub.erase(kInfo.hubId);
270 mUnlinked = true;
271 return pw::OkStatus();
272 }
273
checkValidLocked()274 pw::Status HostHub::checkValidLocked() {
275 if (!mCallback) {
276 ALOGE("APIs invoked on hub %" PRId64
277 " which was not successfully registered.",
278 kInfo.hubId);
279 return pw::Status::FailedPrecondition();
280 } else if (mUnlinked) {
281 ALOGW("Hub %" PRId64 " went down mid-operation", kInfo.hubId);
282 return pw::Status::Aborted();
283 }
284 return pw::OkStatus();
285 }
286
endpointExistsLocked(const EndpointId & id,std::optional<std::string> serviceDescriptor)287 pw::Status HostHub::endpointExistsLocked(
288 const EndpointId &id, std::optional<std::string> serviceDescriptor) {
289 if (id.hubId != kInfo.hubId) {
290 LOGE("Rejecting lookup on unowned endpoint (%" PRId64 ", %" PRId64
291 ") from hub %" PRId64,
292 id.hubId, id.id, kInfo.hubId);
293 return pw::Status::InvalidArgument();
294 }
295 if (auto it = mIdToEndpoint.find(id.id); it != mIdToEndpoint.end()) {
296 if (!serviceDescriptor) return pw::OkStatus();
297 for (const auto &service : it->second.services) {
298 if (service.serviceDescriptor == *serviceDescriptor)
299 return pw::OkStatus();
300 }
301 LOGW("Endpoint (%" PRId64 ", %" PRId64 ") doesn't have service %s",
302 id.hubId, id.id, serviceDescriptor->c_str());
303 }
304 return pw::Status::NotFound();
305 }
306
sessionIdInRangeLocked(uint16_t id)307 bool HostHub::sessionIdInRangeLocked(uint16_t id) {
308 for (auto range : mSessionIdRanges) {
309 if (id >= range.first && id <= range.second) return true;
310 }
311 return false;
312 }
313
checkSessionOpenLocked(uint16_t id)314 pw::Status HostHub::checkSessionOpenLocked(uint16_t id) {
315 PW_TRY_ASSIGN(Session * session, getSessionLocked(id));
316 if (!session->mPendingDestination && !session->mPendingMessageRouter)
317 return pw::OkStatus();
318 LOGE("Session %" PRIu16 " is pending", id);
319 return pw::Status::FailedPrecondition();
320 }
321
getSessionLocked(uint16_t id)322 pw::Result<HostHub::Session *> HostHub::getSessionLocked(uint16_t id) {
323 auto sessionIt = mIdToSession.find(id);
324 if (sessionIt == mIdToSession.end()) {
325 LOGE("Did not find expected session %" PRIu16 " in hub %" PRId64, id,
326 kInfo.hubId);
327 return pw::Status::NotFound();
328 }
329 return &sessionIt->second;
330 }
331
createHostHub(std::shared_ptr<IEndpointCallback> callback,const HubInfo & info,uid_t uid,pid_t pid)332 pw::Result<std::shared_ptr<HostHub>> MessageHubManager::createHostHub(
333 std::shared_ptr<IEndpointCallback> callback, const HubInfo &info, uid_t uid,
334 pid_t pid) {
335 if (info.hubId == kContextHubServiceHubId && uid != kSystemServerUid) {
336 LOGE("(pid %" PRId32 ", uid %" PRId32
337 ") attempting to impersonate ContextHubService",
338 pid, uid);
339 return pw::Status::PermissionDenied();
340 }
341 std::lock_guard lock(mLock);
342 if (mIdToHostHub.count(info.hubId)) return pw::Status::AlreadyExists();
343 std::shared_ptr<HostHub> hub(new HostHub(*this, std::move(callback), info));
344 if (!hub->mCallback) return pw::Status::Internal();
345 mIdToHostHub.insert({info.hubId, hub});
346 LOGI("Registered host hub %" PRId64, info.hubId);
347 return hub;
348 }
349
getHostHub(int64_t id)350 std::shared_ptr<HostHub> MessageHubManager::getHostHub(int64_t id) {
351 std::lock_guard lock(mLock);
352 if (auto it = mIdToHostHub.find(id); it != mIdToHostHub.end())
353 return it->second;
354 return {};
355 }
356
forEachHostHub(std::function<void (HostHub & hub)> fn)357 void MessageHubManager::forEachHostHub(std::function<void(HostHub &hub)> fn) {
358 std::list<std::shared_ptr<HostHub>> hubs;
359 {
360 std::lock_guard lock(mLock);
361 for (auto &[id, hub] : mIdToHostHub) hubs.push_back(hub);
362 }
363 for (auto &hub : hubs) fn(*hub);
364 }
365
initEmbeddedState()366 void MessageHubManager::initEmbeddedState() {
367 std::lock_guard lock(mLock);
368 mIdToEmbeddedHub.clear();
369 mIdToEmbeddedHubReady = true;
370 }
371
clearEmbeddedState()372 void MessageHubManager::clearEmbeddedState() {
373 std::lock_guard lock(mLock);
374 mIdToEmbeddedHubReady = false;
375
376 // Clear embedded hub state, caching the list of now removed endpoints.
377 std::vector<EndpointId> endpoints;
378 for (const auto &[hubId, hub] : mIdToEmbeddedHub) {
379 for (const auto &[endpointId, endpoint] : hub.idToEndpoint)
380 if (endpoint.second) endpoints.push_back(endpoint.first.id);
381 }
382 mIdToEmbeddedHub.clear();
383
384 // For each host hub, close all sessions and send all removed endpoints.
385 for (const auto &[hubId, hub] : mIdToHostHub) {
386 ::android::base::ScopedLockAssertion lockAssertion(hub->mManager.mLock);
387 for (const auto &[sessionId, session] : hub->mIdToSession)
388 hub->mCallback->onCloseEndpointSession(sessionId, Reason::HUB_RESET);
389 hub->mCallback->onEndpointStopped(endpoints, Reason::HUB_RESET);
390 }
391 }
392
addEmbeddedHub(const HubInfo & hub)393 void MessageHubManager::addEmbeddedHub(const HubInfo &hub) {
394 std::lock_guard lock(mLock);
395 if (!mIdToEmbeddedHubReady) {
396 LOGW("Skipping embedded hub registration before initEmbeddedState()");
397 return;
398 }
399 if (mIdToEmbeddedHub.count(hub.hubId)) return;
400 mIdToEmbeddedHub[hub.hubId].info = hub;
401 }
402
removeEmbeddedHub(int64_t id)403 void MessageHubManager::removeEmbeddedHub(int64_t id) {
404 std::lock_guard lock(mLock);
405
406 // Get the list of endpoints being removed and remove the hub.
407 std::vector<EndpointId> endpoints;
408 auto it = mIdToEmbeddedHub.find(id);
409 if (it == mIdToEmbeddedHub.end()) return;
410 for (const auto &[endpointId, info] : it->second.idToEndpoint)
411 if (info.second) endpoints.push_back(info.first.id);
412 mIdToEmbeddedHub.erase(it);
413
414 // For each host hub, determine which sessions if any are now closed and send
415 // notifications as appropriate. Also send the list of removed endpoints.
416 for (auto &[hostHubId, hub] : mIdToHostHub) {
417 ::android::base::ScopedLockAssertion lockAssertion(hub->mManager.mLock);
418 std::vector<uint16_t> closedSessions;
419 for (const auto &[sessionId, session] : hub->mIdToSession) {
420 if (session.mEmbeddedEndpoint.hubId == id) {
421 hub->mCallback->onCloseEndpointSession(sessionId, Reason::HUB_RESET);
422 closedSessions.push_back(sessionId);
423 }
424 }
425 for (auto session : closedSessions) hub->mIdToSession.erase(session);
426 hub->mCallback->onEndpointStopped(endpoints, Reason::HUB_RESET);
427 }
428 }
429
getEmbeddedHubs() const430 std::vector<HubInfo> MessageHubManager::getEmbeddedHubs() const {
431 std::lock_guard lock(mLock);
432 std::vector<HubInfo> hubs;
433 for (const auto &[id, hub] : mIdToEmbeddedHub) hubs.push_back(hub.info);
434 return hubs;
435 }
436
addEmbeddedEndpoint(const EndpointInfo & endpoint)437 void MessageHubManager::addEmbeddedEndpoint(const EndpointInfo &endpoint) {
438 std::lock_guard lock(mLock);
439 if (!mIdToEmbeddedHubReady) {
440 LOGW("Skipping embedded endpoint registration before initEmbeddedState()");
441 return;
442 }
443 addEmbeddedEndpointLocked(endpoint);
444 }
445
addEmbeddedEndpointService(const EndpointId & endpoint,const Service & service)446 void MessageHubManager::addEmbeddedEndpointService(const EndpointId &endpoint,
447 const Service &service) {
448 std::lock_guard lock(mLock);
449 if (!mIdToEmbeddedHubReady) {
450 LOGW("Skipping embedded endpoint registration before initEmbeddedState()");
451 return;
452 }
453 auto statusOrEndpoint = lookupEmbeddedEndpointLocked(endpoint);
454 if (!statusOrEndpoint.ok()) return;
455 if ((*statusOrEndpoint)->second) {
456 LOGE("Adding service to embedded endpoint after ready");
457 return;
458 }
459 (*statusOrEndpoint)->first.services.push_back(service);
460 }
461
setEmbeddedEndpointReady(const EndpointId & id)462 void MessageHubManager::setEmbeddedEndpointReady(const EndpointId &id) {
463 std::lock_guard lock(mLock);
464 if (!mIdToEmbeddedHubReady) {
465 LOGW("Skipping embedded endpoint registration before initEmbeddedState()");
466 return;
467 }
468 auto statusOrEndpoint = lookupEmbeddedEndpointLocked(id);
469 if (!statusOrEndpoint.ok() || (*statusOrEndpoint)->second) return;
470 (*statusOrEndpoint)->second = true;
471 for (auto &[hostHubId, hub] : mIdToHostHub) {
472 ::android::base::ScopedLockAssertion lockAssertion(hub->mManager.mLock);
473 hub->mCallback->onEndpointStarted({(*statusOrEndpoint)->first});
474 }
475 }
476
getEmbeddedEndpoints() const477 std::vector<EndpointInfo> MessageHubManager::getEmbeddedEndpoints() const {
478 std::lock_guard lock(mLock);
479 std::vector<EndpointInfo> endpoints;
480 for (const auto &[id, hub] : mIdToEmbeddedHub) {
481 for (const auto &[endptId, endptInfo] : hub.idToEndpoint)
482 if (endptInfo.second) endpoints.push_back(endptInfo.first);
483 }
484 return endpoints;
485 }
486
removeEmbeddedEndpoint(const EndpointId & id)487 void MessageHubManager::removeEmbeddedEndpoint(const EndpointId &id) {
488 std::lock_guard lock(mLock);
489 auto hubIt = mIdToEmbeddedHub.find(id.hubId);
490 if (hubIt == mIdToEmbeddedHub.end()) return;
491 if (!hubIt->second.idToEndpoint.erase(id.id)) return;
492
493 // For each host hub, determine which sessions if any are now closed and send
494 // notifications as appropriate. Also send the removed endpoint notification.
495 for (auto &[hostHubId, hub] : mIdToHostHub) {
496 ::android::base::ScopedLockAssertion lockAssertion(hub->mManager.mLock);
497 std::vector<uint16_t> closedSessions;
498 for (const auto &[sessionId, session] : hub->mIdToSession) {
499 if (session.mEmbeddedEndpoint == id) {
500 hub->mCallback->onCloseEndpointSession(sessionId,
501 Reason::ENDPOINT_GONE);
502 closedSessions.push_back(sessionId);
503 }
504 }
505 for (auto session : closedSessions) hub->mIdToSession.erase(session);
506 hub->mCallback->onEndpointStopped({id}, Reason::ENDPOINT_GONE);
507 }
508 }
509
RealDeathRecipient()510 MessageHubManager::RealDeathRecipient::RealDeathRecipient() {
511 mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
512 AIBinder_DeathRecipient_new(&MessageHubManager::onClientDeath));
513 AIBinder_DeathRecipient_setOnUnlinked(
514 mDeathRecipient.get(), /*onUnlinked= */ [](void *cookie) {
515 LOGD("Callback is unlinked. Releasing the death recipient cookie.");
516 delete static_cast<HostHub::DeathRecipientCookie *>(cookie);
517 });
518 }
519
linkCallback(const std::shared_ptr<IEndpointCallback> & callback,HostHub::DeathRecipientCookie * cookie)520 pw::Status MessageHubManager::RealDeathRecipient::linkCallback(
521 const std::shared_ptr<IEndpointCallback> &callback,
522 HostHub::DeathRecipientCookie *cookie) {
523 return AIBinder_linkToDeath(callback->asBinder().get(), mDeathRecipient.get(),
524 cookie) == STATUS_OK
525 ? pw::OkStatus()
526 : pw::Status::Internal();
527 }
528
unlinkCallback(const std::shared_ptr<IEndpointCallback> & callback,HostHub::DeathRecipientCookie * cookie)529 pw::Status MessageHubManager::RealDeathRecipient::unlinkCallback(
530 const std::shared_ptr<IEndpointCallback> &callback,
531 HostHub::DeathRecipientCookie *cookie) {
532 return AIBinder_unlinkToDeath(callback->asBinder().get(),
533 mDeathRecipient.get(), cookie) == STATUS_OK
534 ? pw::OkStatus()
535 : pw::Status::NotFound();
536 }
537
onClientDeath(void * cookie)538 void MessageHubManager::onClientDeath(void *cookie) {
539 auto *cookieData = reinterpret_cast<HostHub::DeathRecipientCookie *>(cookie);
540 LOGW("Process hosting hub %" PRId64 " died", cookieData->hubId);
541 MessageHubManager *manager = cookieData->manager;
542 std::shared_ptr<HostHub> hub = manager->getHostHub(cookieData->hubId);
543 // NOTE: if IEndpointCommunication.unregister() was called simultaneously, hub
544 // may be null or unlinkFromManager() may fail.
545 if (hub) {
546 manager->mHostHubDownCb([hubPtr = hub.get()]() -> pw::Result<int64_t> {
547 PW_TRY(hubPtr->unlinkFromManager());
548 return hubPtr->id();
549 });
550 }
551 }
552
addEmbeddedEndpointLocked(const EndpointInfo & endpoint)553 void MessageHubManager::addEmbeddedEndpointLocked(
554 const EndpointInfo &endpoint) {
555 auto it = mIdToEmbeddedHub.find(endpoint.id.hubId);
556 if (it == mIdToEmbeddedHub.end()) {
557 LOGW("Could not find hub %" PRId64 " for endpoint %" PRId64,
558 endpoint.id.hubId, endpoint.id.id);
559 return;
560 }
561 it->second.idToEndpoint.insert({endpoint.id.id, {endpoint, false}});
562 }
563
embeddedEndpointExistsLocked(const EndpointId & id,std::optional<std::string> serviceDescriptor)564 pw::Status MessageHubManager::embeddedEndpointExistsLocked(
565 const EndpointId &id, std::optional<std::string> serviceDescriptor) {
566 PW_TRY_ASSIGN(const auto *endpoint, lookupEmbeddedEndpointLocked(id));
567 if (!endpoint->second) {
568 LOGW("Accessing remote endpoint (%" PRId64 ", %" PRId64 ") before ready",
569 id.hubId, id.id);
570 return pw::Status::NotFound();
571 }
572 if (!serviceDescriptor) return pw::OkStatus();
573 for (const auto &service : endpoint->first.services) {
574 if (service.serviceDescriptor == *serviceDescriptor) return pw::OkStatus();
575 }
576 LOGW("Endpoint (%" PRId64 ", %" PRId64 ") doesn't have service %s", id.hubId,
577 id.id, serviceDescriptor->c_str());
578 return pw::Status::NotFound();
579 }
580
581 pw::Result<std::pair<EndpointInfo, bool> *>
lookupEmbeddedEndpointLocked(const EndpointId & id)582 MessageHubManager::lookupEmbeddedEndpointLocked(const EndpointId &id) {
583 auto hubIt = mIdToEmbeddedHub.find(id.hubId);
584 if (hubIt != mIdToEmbeddedHub.end()) {
585 auto it = hubIt->second.idToEndpoint.find(id.id);
586 if (it != hubIt->second.idToEndpoint.end()) return &(it->second);
587 }
588 LOGW("Could not find remote endpoint (%" PRId64 ", %" PRId64 ")", id.hubId,
589 id.id);
590 return pw::Status::NotFound();
591 }
592
593 } // namespace android::hardware::contexthub::common::implementation
594