| // Copyright 2020 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/developer/forensics/exceptions/handler/component_lookup.h" |
| |
| #include <lib/syslog/cpp/macros.h> |
| |
| #include "src/developer/forensics/utils/errors.h" |
| #include "src/developer/forensics/utils/fidl/oneshot_ptr.h" |
| #include "src/developer/forensics/utils/fit/promise.h" |
| #include "src/lib/fxl/macros.h" |
| |
| namespace forensics { |
| namespace exceptions { |
| namespace handler { |
| namespace { |
| |
| using fuchsia::sys::internal::CrashIntrospect_FindComponentByThreadKoid_Result; |
| using fuchsia::sys::internal::SourceIdentity; |
| |
| // Wraps around fuchsia::sys::internal::CrashIntrospectPtr to handle establishing the connection, |
| // losing the connection, waiting for the callback, enforcing a timeout, etc. |
| // |
| // GetSourceIdentity() is expected to be called only once. |
| class ComponentLookup { |
| public: |
| // fuchsia.sys.internal.CrashIntrospect is expected to be in |services|. |
| ComponentLookup(async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services) |
| : introspect_(dispatcher, services) {} |
| |
| ::fit::promise<SourceIdentity> GetSourceIdentity(zx_koid_t process_koid, fit::Timeout timeout); |
| |
| private: |
| fidl::OneShotPtr<fuchsia::sys::internal::CrashIntrospect, SourceIdentity> introspect_; |
| }; |
| |
| ::fit::promise<SourceIdentity> ComponentLookup::GetSourceIdentity(zx_koid_t thread_koid, |
| fit::Timeout timeout) { |
| introspect_->FindComponentByThreadKoid( |
| thread_koid, [this](CrashIntrospect_FindComponentByThreadKoid_Result result) { |
| if (introspect_.IsAlreadyDone()) { |
| return; |
| } |
| |
| if (result.is_response()) { |
| introspect_.CompleteOk(std::move(result.response().component_info)); |
| } else { |
| // ZX_ERR_NOT_FOUND most likely means a thread from a process outside a component, |
| // which is not an error. |
| if (result.err() != ZX_ERR_NOT_FOUND) { |
| FX_PLOGS(WARNING, result.err()) << "Failed FindComponentByProcessKoid"; |
| } |
| |
| introspect_.CompleteError(Error::kDefault); |
| } |
| }); |
| |
| return introspect_.WaitForDone(std::move(timeout)).or_else([](const Error& error) { |
| return ::fit::error(); |
| }); |
| } |
| |
| } // namespace |
| |
| ::fit::promise<SourceIdentity> GetComponentSourceIdentity( |
| async_dispatcher_t* dispatcher, std::shared_ptr<sys::ServiceDirectory> services, |
| fit::Timeout timeout, zx_koid_t thread_koid) { |
| auto component_lookup = std::make_unique<ComponentLookup>(dispatcher, services); |
| |
| // We must store the promise in a variable due to the fact that the order of evaluation of |
| // function parameters is undefined. |
| auto component = component_lookup->GetSourceIdentity(thread_koid, std::move(timeout)); |
| return fit::ExtendArgsLifetimeBeyondPromise(/*promise=*/std::move(component), |
| /*args=*/std::move(component_lookup)); |
| } |
| |
| } // namespace handler |
| } // namespace exceptions |
| } // namespace forensics |