| // Copyright 2019 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 <lib/async-loop/cpp/loop.h> |
| #include <lib/async-loop/default.h> |
| #include <lib/component/incoming/cpp/protocol.h> |
| #include <lib/component/incoming/cpp/service_member_watcher.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/scheduler/role.h> |
| #include <lib/trace-provider/provider.h> |
| |
| #include <memory> |
| |
| #include "src/developer/memory/metrics/capture.h" |
| #include "src/developer/memory/monitor/imminent_oom_observer.h" |
| #include "src/developer/memory/monitor/monitor.h" |
| |
| namespace { |
| std::optional<fidl::Client<fuchsia_hardware_ram_metrics::Device>> GetRamDevice( |
| async_dispatcher_t* dispatcher) { |
| // Look for optional RAM device that provides bandwidth measurement interface. |
| zx::result device = |
| component::SyncServiceMemberWatcher<fuchsia_hardware_ram_metrics::Service::Device>() |
| .GetNextInstance(true); |
| if (device.is_error()) { |
| FX_LOGS(INFO) << "CANNOT collect memory bandwidth measurements. error_code: " |
| << device.status_string(); |
| return std::nullopt; |
| } |
| FX_LOGS(INFO) << "Will collect memory bandwidth measurements."; |
| return fidl::Client<fuchsia_hardware_ram_metrics::Device>(std::move(*device), dispatcher); |
| } |
| } // namespace |
| |
| int main(int argc, const char** argv) { |
| async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); |
| FX_LOGS(DEBUG) << argv[0] << ": starting"; |
| |
| trace::TraceProviderWithFdio trace_provider(loop.dispatcher(), monitor::Monitor::kTraceName); |
| // Lower the priority. |
| zx_status_t status = fuchsia_scheduler::SetRoleForThisThread("fuchsia.memory-monitor.main"); |
| FX_CHECK(status == ZX_OK) << "Set scheduler role status: " << zx_status_get_string(status); |
| |
| auto maker = memory::CaptureMaker::Create(memory::CreateDefaultOS()); |
| if (maker.is_error()) { |
| FX_LOGS(ERROR) << "Error getting capture state: " << zx_status_get_string(maker.error_value()); |
| exit(EXIT_FAILURE); |
| } |
| |
| zx::result pressure_client_end = component::Connect<fuchsia_memorypressure::Provider>(); |
| if (!pressure_client_end.is_ok()) { |
| FX_LOGS(ERROR) << "Error connecting to FIDL fuchsia.memorypressure.Provider: " |
| << pressure_client_end.status_string(); |
| exit(-1); |
| } |
| auto pressure_provider = fidl::Client{std::move(*pressure_client_end), loop.dispatcher()}; |
| |
| auto root_job_client_end = component::Connect<fuchsia_kernel::RootJobForInspect>(); |
| if (!root_job_client_end.is_ok()) { |
| FX_LOGS(ERROR) << "Error connecting to root job: " << root_job_client_end.error_value(); |
| exit(-1); |
| } |
| |
| auto root_job = fidl::WireCall(*root_job_client_end)->Get(); |
| if (root_job.status() != ZX_OK) { |
| FX_LOGS(ERROR) << "Error getting root job: " << root_job.status(); |
| exit(-1); |
| } |
| zx_handle_t imminent_oom_event_handle; |
| zx_status_t imminent_oom_status = zx_system_get_event( |
| root_job->job.get(), ZX_SYSTEM_EVENT_IMMINENT_OUT_OF_MEMORY, &imminent_oom_event_handle); |
| if (imminent_oom_status != ZX_OK) { |
| FX_LOGS(ERROR) << "zx_system_get_event [IMMINENT-OOM] returned " |
| << zx_status_get_string(imminent_oom_status); |
| exit(-1); |
| } |
| monitor::ImminentOomEventObserver imminent_oom_observer{imminent_oom_event_handle}; |
| |
| std::optional<fidl::Client<fuchsia_metrics::MetricEventLoggerFactory>> factory; |
| { |
| zx::result client_end = component::Connect<fuchsia_metrics::MetricEventLoggerFactory>(); |
| if (!client_end.is_ok()) { |
| FX_LOGS(ERROR) << "Unable to get metrics.MetricEventLoggerFactory."; |
| } else { |
| factory.emplace(std::move(*client_end), loop.dispatcher()); |
| } |
| } |
| auto app = std::make_unique<monitor::Monitor>( |
| loop.dispatcher(), memory_monitor_config::Config::TakeFromStartupHandle(), std::move(*maker), |
| std::move(pressure_provider), &imminent_oom_observer, std::move(factory), |
| GetRamDevice(loop.dispatcher())); |
| component::OutgoingDirectory outgoing = component::OutgoingDirectory(loop.dispatcher()); |
| zx::result result = outgoing.AddProtocol<fuchsia_memory_inspection::Collector>(std::move(app)); |
| FX_CHECK(result.is_ok()); |
| |
| result = outgoing.ServeFromStartupInfo(); |
| if (result.is_error()) { |
| FX_LOGS(ERROR) << "Failed to serve the outgoing directory from startup info: " |
| << result.status_string(); |
| return -1; |
| } |
| loop.Run(); |
| FX_LOGS(DEBUG) << argv[0] << ": exiting"; |
| return 0; |
| } |