From c4608bbfd19626538be29b2ab2da145d712fdc81 Mon Sep 17 00:00:00 2001 From: Michael Brase Date: Mon, 29 Jan 2024 22:26:47 -0600 Subject: [PATCH] Use structured logging on Fuchsia (flutter/engine#49918) This change migrates off of the old fuchsia logging apis to use the structured logging apis. The initial FIDL connection is made during global initialization (before main()) and the initial minimum log level is queried from the system. Later on, once the main loop is initialized, we setup an async task to listen for additional log interest changes from the system. The advantage of doing this on the main loop is that we avoid spawning an additional background thread in the process (the legacy logging apis use the background thread approach). One added benefit of this change is it reduces the size of the dart/flutter runner far packages by about 250kb in release mode, because libsyslog.so and libbackend_fuchsia_globals.so are no longer needed. flutter/flutter#141924 ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide] and the [C++, Objective-C, Java style guides]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I added new tests to check the change I am making or feature I am adding, or the PR is [test-exempt]. See [testing the engine] for instructions on writing and running engine tests. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I signed the [CLA]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style [testing the engine]: https://github.com/flutter/flutter/wiki/Testing-the-engine [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --- .../flutter/ci/licenses_golden/excluded_files | 1 + .../ci/licenses_golden/licenses_flutter | 8 ++ engine/src/flutter/fml/BUILD.gn | 20 ++- engine/src/flutter/fml/log_settings.cc | 12 -- engine/src/flutter/fml/logging.cc | 81 +++++++++-- .../platform/fuchsia/log_interest_listener.cc | 50 +++++++ .../platform/fuchsia/log_interest_listener.h | 37 +++++ .../log_interest_listener_unittests.cc | 127 ++++++++++++++++++ .../flutter/fml/platform/fuchsia/log_state.cc | 66 +++++++++ .../flutter/fml/platform/fuchsia/log_state.h | 55 ++++++++ .../platform/fuchsia/dart_runner/main.cc | 9 +- .../shell/platform/fuchsia/flutter/main.cc | 9 ++ .../testing/fuchsia/meta/test_suite.cml | 3 + .../flutter/tools/fuchsia/fuchsia_libs.gni | 8 -- 14 files changed, 450 insertions(+), 36 deletions(-) create mode 100644 engine/src/flutter/fml/platform/fuchsia/log_interest_listener.cc create mode 100644 engine/src/flutter/fml/platform/fuchsia/log_interest_listener.h create mode 100644 engine/src/flutter/fml/platform/fuchsia/log_interest_listener_unittests.cc create mode 100644 engine/src/flutter/fml/platform/fuchsia/log_state.cc create mode 100644 engine/src/flutter/fml/platform/fuchsia/log_state.h diff --git a/engine/src/flutter/ci/licenses_golden/excluded_files b/engine/src/flutter/ci/licenses_golden/excluded_files index 44c5a060fe..7706745f1f 100644 --- a/engine/src/flutter/ci/licenses_golden/excluded_files +++ b/engine/src/flutter/ci/licenses_golden/excluded_files @@ -106,6 +106,7 @@ ../../../flutter/fml/platform/darwin/string_range_sanitization_unittests.mm ../../../flutter/fml/platform/darwin/weak_nsobject_arc_unittests.mm ../../../flutter/fml/platform/darwin/weak_nsobject_unittests.mm +../../../flutter/fml/platform/fuchsia/log_interest_listener_unittests.cc ../../../flutter/fml/platform/win/file_win_unittests.cc ../../../flutter/fml/platform/win/wstring_conversion_unittests.cc ../../../flutter/fml/raster_thread_merger_unittests.cc diff --git a/engine/src/flutter/ci/licenses_golden/licenses_flutter b/engine/src/flutter/ci/licenses_golden/licenses_flutter index 0404f6572f..513f30ec14 100644 --- a/engine/src/flutter/ci/licenses_golden/licenses_flutter +++ b/engine/src/flutter/ci/licenses_golden/licenses_flutter @@ -4856,6 +4856,10 @@ ORIGIN: ../../../flutter/fml/platform/darwin/string_range_sanitization.h + ../.. ORIGIN: ../../../flutter/fml/platform/darwin/string_range_sanitization.mm + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/darwin/weak_nsobject.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/darwin/weak_nsobject.mm + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/fml/platform/fuchsia/log_interest_listener.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/fml/platform/fuchsia/log_interest_listener.h + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/fml/platform/fuchsia/log_state.cc + ../../../flutter/LICENSE +ORIGIN: ../../../flutter/fml/platform/fuchsia/log_state.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/fuchsia/message_loop_fuchsia.cc + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/fuchsia/message_loop_fuchsia.h + ../../../flutter/LICENSE ORIGIN: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc + ../../../flutter/LICENSE @@ -7701,6 +7705,10 @@ FILE: ../../../flutter/fml/platform/darwin/string_range_sanitization.h FILE: ../../../flutter/fml/platform/darwin/string_range_sanitization.mm FILE: ../../../flutter/fml/platform/darwin/weak_nsobject.h FILE: ../../../flutter/fml/platform/darwin/weak_nsobject.mm +FILE: ../../../flutter/fml/platform/fuchsia/log_interest_listener.cc +FILE: ../../../flutter/fml/platform/fuchsia/log_interest_listener.h +FILE: ../../../flutter/fml/platform/fuchsia/log_state.cc +FILE: ../../../flutter/fml/platform/fuchsia/log_state.h FILE: ../../../flutter/fml/platform/fuchsia/message_loop_fuchsia.cc FILE: ../../../flutter/fml/platform/fuchsia/message_loop_fuchsia.h FILE: ../../../flutter/fml/platform/fuchsia/paths_fuchsia.cc diff --git a/engine/src/flutter/fml/BUILD.gn b/engine/src/flutter/fml/BUILD.gn index 46a0df5078..aac98dc2a1 100644 --- a/engine/src/flutter/fml/BUILD.gn +++ b/engine/src/flutter/fml/BUILD.gn @@ -214,6 +214,10 @@ source_set("fml") { if (is_fuchsia) { sources += [ + "platform/fuchsia/log_interest_listener.cc", + "platform/fuchsia/log_interest_listener.h", + "platform/fuchsia/log_state.cc", + "platform/fuchsia/log_state.h", "platform/fuchsia/message_loop_fuchsia.cc", "platform/fuchsia/message_loop_fuchsia.h", "platform/fuchsia/paths_fuchsia.cc", @@ -222,10 +226,13 @@ source_set("fml") { ] public_deps += [ + "$fuchsia_sdk_root/fidl:fuchsia.diagnostics", + "$fuchsia_sdk_root/fidl:fuchsia.logger", "$fuchsia_sdk_root/pkg:async-cpp", "$fuchsia_sdk_root/pkg:async-loop-cpp", "$fuchsia_sdk_root/pkg:async-loop-default", - "$fuchsia_sdk_root/pkg:syslog", + "$fuchsia_sdk_root/pkg:component_incoming_cpp", + "$fuchsia_sdk_root/pkg:syslog_structured_backend", "$fuchsia_sdk_root/pkg:trace", "$fuchsia_sdk_root/pkg:trace-engine", "$fuchsia_sdk_root/pkg:zx", @@ -377,6 +384,10 @@ if (enable_unittests) { ] } + if (is_fuchsia) { + sources += [ "platform/fuchsia/log_interest_listener_unittests.cc" ] + } + if (is_win) { sources += [ "platform/win/file_win_unittests.cc", @@ -392,8 +403,13 @@ if (enable_unittests) { "//flutter/testing", ] - # This is needed for //third_party/googletest for linking zircon symbols. if (is_fuchsia) { + deps += [ + "$fuchsia_sdk_root/pkg:async-loop-testing", + "$fuchsia_sdk_root/pkg:sys_component_cpp_testing", + ] + + # This is needed for //third_party/googletest for linking zircon symbols. libs = [ "${fuchsia_sdk_path}/arch/${target_cpu}/sysroot/lib/libzircon.so" ] } diff --git a/engine/src/flutter/fml/log_settings.cc b/engine/src/flutter/fml/log_settings.cc index b81e78a3d7..8584517c1a 100644 --- a/engine/src/flutter/fml/log_settings.cc +++ b/engine/src/flutter/fml/log_settings.cc @@ -15,10 +15,6 @@ #include "flutter/fml/log_level.h" #include "flutter/fml/logging.h" -#if defined(OS_FUCHSIA) -#include -#endif - namespace fml { namespace state { @@ -31,14 +27,6 @@ void SetLogSettings(const LogSettings& settings) { // Validate the new settings as we set them. state::g_log_settings.min_log_level = std::min(kLogFatal, settings.min_log_level); -#if defined(OS_FUCHSIA) - // Syslog should accept all logs, since filtering by severity is done by fml. - fx_logger_t* logger = fx_log_get_logger(); - if (logger) { - fx_logger_set_min_severity(logger, - std::numeric_limits::min()); - } -#endif } LogSettings GetLogSettings() { diff --git a/engine/src/flutter/fml/logging.cc b/engine/src/flutter/fml/logging.cc index 0d48943980..bedd82017f 100644 --- a/engine/src/flutter/fml/logging.cc +++ b/engine/src/flutter/fml/logging.cc @@ -16,7 +16,10 @@ #elif defined(FML_OS_IOS) #include #elif defined(OS_FUCHSIA) -#include +#include +#include +#include +#include "flutter/fml/platform/fuchsia/log_state.h" #endif namespace fml { @@ -33,6 +36,7 @@ const char* GetNameForLogSeverity(LogSeverity severity) { } return "UNKNOWN"; } +#endif const char* StripDots(const char* path) { while (strncmp(path, "../", 3) == 0) { @@ -48,6 +52,44 @@ const char* StripPath(const char* path) { } return path; } + +#if defined(OS_FUCHSIA) + +zx_koid_t GetKoid(zx_handle_t handle) { + zx_info_handle_basic_t info; + zx_status_t status = zx_object_get_info(handle, ZX_INFO_HANDLE_BASIC, &info, + sizeof(info), nullptr, nullptr); + return status == ZX_OK ? info.koid : ZX_KOID_INVALID; +} + +thread_local zx_koid_t tls_thread_koid{ZX_KOID_INVALID}; + +zx_koid_t GetCurrentThreadKoid() { + if (unlikely(tls_thread_koid == ZX_KOID_INVALID)) { + tls_thread_koid = GetKoid(zx_thread_self()); + } + ZX_DEBUG_ASSERT(tls_thread_koid != ZX_KOID_INVALID); + return tls_thread_koid; +} + +static zx_koid_t pid = GetKoid(zx_process_self()); + +static thread_local zx_koid_t tid = GetCurrentThreadKoid(); + +std::string GetProcessName(zx_handle_t handle) { + char process_name[ZX_MAX_NAME_LEN]; + zx_status_t status = zx_object_get_property( + handle, ZX_PROP_NAME, &process_name, sizeof(process_name)); + if (status != ZX_OK) { + process_name[0] = '\0'; + } + return process_name; +} + +static std::string process_name = GetProcessName(zx_process_self()); + +static const zx::socket& socket = LogState::Default().socket(); + #endif } // namespace @@ -56,7 +98,9 @@ LogMessage::LogMessage(LogSeverity severity, const char* file, int line, const char* condition) - : severity_(severity), file_(file), line_(line) { + : severity_(severity), + file_(severity > kLogInfo ? StripDots(file) : StripPath(file)), + line_(line) { #if !defined(OS_FUCHSIA) stream_ << "["; if (severity >= kLogInfo) { @@ -64,8 +108,7 @@ LogMessage::LogMessage(LogSeverity severity, } else { stream_ << "VERBOSE" << -severity; } - stream_ << ":" << (severity > kLogInfo ? StripDots(file_) : StripPath(file_)) - << "(" << line_ << ")] "; + stream_ << ":" << file_ << "(" << line_ << ")] "; #endif if (condition) { @@ -127,30 +170,42 @@ LogMessage::~LogMessage() { #elif defined(FML_OS_IOS) syslog(LOG_ALERT, "%s", stream_.str().c_str()); #elif defined(OS_FUCHSIA) - fx_log_severity_t fx_severity; + FuchsiaLogSeverity severity; switch (severity_) { case kLogInfo: - fx_severity = FX_LOG_INFO; + severity = FUCHSIA_LOG_INFO; break; case kLogWarning: - fx_severity = FX_LOG_WARNING; + severity = FUCHSIA_LOG_WARNING; break; case kLogError: - fx_severity = FX_LOG_ERROR; + severity = FUCHSIA_LOG_ERROR; break; case kLogFatal: - fx_severity = FX_LOG_FATAL; + severity = FUCHSIA_LOG_FATAL; break; default: if (severity_ < 0) { - fx_severity = fx_log_severity_from_verbosity(-severity_); + severity = FUCHSIA_LOG_DEBUG; } else { // Unknown severity. Use INFO. - fx_severity = FX_LOG_INFO; + severity = FUCHSIA_LOG_INFO; } + break; } - fx_logger_log_with_source(fx_log_get_logger(), fx_severity, nullptr, file_, - line_, stream_.str().c_str()); + fuchsia_syslog::LogBuffer buffer; + buffer.BeginRecord(severity, std::string_view(file_), line_, + std::string_view(stream_.str()), socket.borrow(), 0, pid, + tid); + if (!process_name.empty()) { + buffer.WriteKeyValue("tag", process_name); + } + if (auto tags_ptr = LogState::Default().tags()) { + for (auto& tag : *tags_ptr) { + buffer.WriteKeyValue("tag", tag); + } + } + buffer.FlushRecord(); #else // Don't use std::cerr here, because it may not be initialized properly yet. fprintf(stderr, "%s", stream_.str().c_str()); diff --git a/engine/src/flutter/fml/platform/fuchsia/log_interest_listener.cc b/engine/src/flutter/fml/platform/fuchsia/log_interest_listener.cc new file mode 100644 index 0000000000..fe123c5a37 --- /dev/null +++ b/engine/src/flutter/fml/platform/fuchsia/log_interest_listener.cc @@ -0,0 +1,50 @@ +// Copyright 2013 The Flutter 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 "flutter/fml/platform/fuchsia/log_interest_listener.h" + +#include +#include +#include + +#include "flutter/fml/log_level.h" +#include "flutter/fml/log_settings.h" + +namespace fml { + +void LogInterestListener::AsyncWaitForInterestChanged() { + log_sink_->WaitForInterestChange().Then( + [this](fidl::Result& + interest_result) { + if (interest_result.is_error()) { + // Gracefully terminate on loop shutdown + auto error = interest_result.error_value(); + ZX_ASSERT_MSG(error.is_framework_error() && + error.framework_error().is_dispatcher_shutdown(), + "%s", error.FormatDescription().c_str()); + return; + } + HandleInterestChange(interest_result->data()); + AsyncWaitForInterestChanged(); + }); +} + +void LogInterestListener::HandleInterestChange( + const fuchsia_diagnostics::Interest& interest) { + auto severity = + interest.min_severity().value_or(fuchsia_diagnostics::Severity::kInfo); + if (severity <= fuchsia_diagnostics::Severity::kDebug) { + fml::SetLogSettings({.min_log_level = -1}); // Verbose + } else if (severity <= fuchsia_diagnostics::Severity::kInfo) { + fml::SetLogSettings({.min_log_level = kLogInfo}); + } else if (severity <= fuchsia_diagnostics::Severity::kWarn) { + fml::SetLogSettings({.min_log_level = kLogWarning}); + } else if (severity <= fuchsia_diagnostics::Severity::kError) { + fml::SetLogSettings({.min_log_level = kLogError}); + } else { + fml::SetLogSettings({.min_log_level = kLogFatal}); + } +} + +} // namespace fml diff --git a/engine/src/flutter/fml/platform/fuchsia/log_interest_listener.h b/engine/src/flutter/fml/platform/fuchsia/log_interest_listener.h new file mode 100644 index 0000000000..a8cf9f7853 --- /dev/null +++ b/engine/src/flutter/fml/platform/fuchsia/log_interest_listener.h @@ -0,0 +1,37 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FML_PLATFORM_FUCHSIA_LOG_INTEREST_LISTENER_H_ +#define FLUTTER_FML_PLATFORM_FUCHSIA_LOG_INTEREST_LISTENER_H_ + +#include +#include +#include + +namespace fml { + +// Class to monitor the Fuchsia LogSink service for log interest changes (i.e. +// when the Fuchsia OS requests a change to the minimum log level). +// +// Care should be taken to always use this object on the same thread. +class LogInterestListener { + public: + LogInterestListener(fidl::ClientEnd<::fuchsia_logger::LogSink> client_end, + async_dispatcher_t* dispatcher) + : log_sink_(std::move(client_end), dispatcher) {} + + // Schedules async task to monitor the log sink for log interest changes. + void AsyncWaitForInterestChanged(); + + // Updates the global log settings in response to a log interest change. + static void HandleInterestChange( + const fuchsia_diagnostics::Interest& interest); + + private: + fidl::Client<::fuchsia_logger::LogSink> log_sink_; +}; + +} // namespace fml + +#endif // FLUTTER_FML_PLATFORM_FUCHSIA_LOG_STATE_H_ diff --git a/engine/src/flutter/fml/platform/fuchsia/log_interest_listener_unittests.cc b/engine/src/flutter/fml/platform/fuchsia/log_interest_listener_unittests.cc new file mode 100644 index 0000000000..3f2ae38160 --- /dev/null +++ b/engine/src/flutter/fml/platform/fuchsia/log_interest_listener_unittests.cc @@ -0,0 +1,127 @@ +// Copyright 2013 The Flutter 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "flutter/fml/log_settings.h" +#include "flutter/fml/platform/fuchsia/log_interest_listener.h" +#include "gtest/gtest.h" + +namespace fml { +namespace testing { + +constexpr static char kLogSink[] = "log_sink"; + +class LogInterestListenerFuchsia : public ::loop_fixture::RealLoop, + public ::testing::Test {}; + +TEST_F(LogInterestListenerFuchsia, SeverityChanges) { + ScopedSetLogSettings backup({.min_log_level = kLogInfo}); + { + ::fuchsia_diagnostics::Interest interest; + interest.min_severity(::fuchsia_diagnostics::Severity::kTrace); + LogInterestListener::HandleInterestChange(interest); + EXPECT_EQ(GetMinLogLevel(), -1); // VERBOSE + } + { + ::fuchsia_diagnostics::Interest interest; + interest.min_severity(::fuchsia_diagnostics::Severity::kInfo); + LogInterestListener::HandleInterestChange(interest); + EXPECT_EQ(GetMinLogLevel(), kLogInfo); + } + { + ::fuchsia_diagnostics::Interest interest; + interest.min_severity(::fuchsia_diagnostics::Severity::kError); + LogInterestListener::HandleInterestChange(interest); + EXPECT_EQ(GetMinLogLevel(), kLogError); + } +} + +// Class to mock the server end of a LogSink. +class MockLogSink : public component_testing::LocalComponentImpl, + public fidl::Server { + public: + MockLogSink(fit::closure quitLoop, async_dispatcher_t* dispatcher) + : quit_loop_(std::move(quitLoop)), dispatcher_(dispatcher) {} + + void WaitForInterestChange( + WaitForInterestChangeCompleter::Sync& completer) override { + if (first_call_) { + // If it has not been called before, then return a result right away. + fuchsia_logger::LogSinkWaitForInterestChangeResponse response = { + {.data = {{.min_severity = fuchsia_diagnostics::Severity::kWarn}}}}; + completer.Reply(fit::ok(response)); + first_call_ = false; + } else { + // On the second call, don't return a result. + completer_.emplace(completer.ToAsync()); + quit_loop_(); + } + } + + void Connect(fuchsia_logger::LogSinkConnectRequest& request, + ConnectCompleter::Sync& completer) override {} + + void ConnectStructured( + fuchsia_logger::LogSinkConnectStructuredRequest& request, + ConnectStructuredCompleter::Sync& completer) override {} + + void OnStart() override { + ASSERT_EQ(outgoing()->AddProtocol( + bindings_.CreateHandler(this, dispatcher_, + fidl::kIgnoreBindingClosure)), + ZX_OK); + } + + private: + bool first_call_ = true; + fit::closure quit_loop_; + async_dispatcher_t* dispatcher_; + fidl::ServerBindingGroup bindings_; + std::optional completer_; +}; + +TEST_F(LogInterestListenerFuchsia, AsyncWaitForInterestChange) { + ScopedSetLogSettings backup({.min_log_level = kLogInfo}); + auto realm_builder = component_testing::RealmBuilder::Create(); + realm_builder.AddLocalChild(kLogSink, [&]() { + return std::make_unique(QuitLoopClosure(), dispatcher()); + }); + realm_builder.AddRoute(component_testing::Route{ + .capabilities = {component_testing::Protocol{ + fidl::DiscoverableProtocolName}}, + .source = component_testing::ChildRef{kLogSink}, + .targets = {component_testing::ParentRef()}}); + + auto realm = realm_builder.Build(dispatcher()); + auto cleanup = fit::defer([&]() { + bool complete = false; + realm.Teardown([&](auto result) { complete = true; }); + RunLoopUntil([&]() { return complete; }); + }); + auto client_end = realm.component().Connect(); + ASSERT_TRUE(client_end.is_ok()); + LogInterestListener listener(std::move(client_end.value()), dispatcher()); + listener.AsyncWaitForInterestChanged(); + RunLoop(); + + EXPECT_EQ(GetMinLogLevel(), kLogWarning); +} + +} // namespace testing +} // namespace fml diff --git a/engine/src/flutter/fml/platform/fuchsia/log_state.cc b/engine/src/flutter/fml/platform/fuchsia/log_state.cc new file mode 100644 index 0000000000..92e27c48b4 --- /dev/null +++ b/engine/src/flutter/fml/platform/fuchsia/log_state.cc @@ -0,0 +1,66 @@ +// Copyright 2013 The Flutter 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 "flutter/fml/platform/fuchsia/log_state.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "flutter/fml/platform/fuchsia/log_interest_listener.h" + +namespace fml { + +LogState::LogState() { + // Get channel to log sink + auto client_end = component::Connect(); + ZX_ASSERT(client_end.is_ok()); + fidl::SyncClient log_sink(std::move(*client_end)); + + // Attempts to create a kernel socket object should never fail. + zx::socket local, remote; + zx::socket::create(ZX_SOCKET_DATAGRAM, &local, &remote); + auto result = log_sink->ConnectStructured({{.socket = std::move(remote)}}); + ZX_ASSERT_MSG(result.is_ok(), "%s", + result.error_value().FormatDescription().c_str()); + + // Wait for the first interest change to set the initial minimum logging + // level (should return quickly). + auto interest_result = log_sink->WaitForInterestChange(); + ZX_ASSERT_MSG(interest_result.is_ok(), "%s", + interest_result.error_value().FormatDescription().c_str()); + LogInterestListener::HandleInterestChange(interest_result->data()); + + socket_ = std::move(local); + client_end_ = log_sink.TakeClientEnd(); +} + +fidl::ClientEnd<::fuchsia_logger::LogSink> LogState::TakeClientEnd() { + std::lock_guard lock(mutex_); + return std::move(client_end_); +} + +void LogState::SetTags(const std::initializer_list& tags) { + std::atomic_store(&tags_, + std::make_shared>(tags)); +} + +LogState& LogState::Default() { + static LogState* instance = new LogState(); + return *instance; +} + +} // namespace fml diff --git a/engine/src/flutter/fml/platform/fuchsia/log_state.h b/engine/src/flutter/fml/platform/fuchsia/log_state.h new file mode 100644 index 0000000000..5aa6f646ca --- /dev/null +++ b/engine/src/flutter/fml/platform/fuchsia/log_state.h @@ -0,0 +1,55 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FLUTTER_FML_PLATFORM_FUCHSIA_LOG_CONNECTION_H_ +#define FLUTTER_FML_PLATFORM_FUCHSIA_LOG_CONNECTION_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace fml { + +// Class for holding the global connection to the Fuchsia LogSink service. +class LogState { + public: + // Connects to the Fuchsia LogSink service. + LogState(); + + // Get the socket for sending log messages. + const zx::socket& socket() const { return socket_; } + + // Get the current list of tags. + std::shared_ptr> tags() const { + return std::atomic_load(&tags_); + } + + // Take ownership of the log sink channel (e.g. for LogInterestListener). + // This is thread-safe. + fidl::ClientEnd<::fuchsia_logger::LogSink> TakeClientEnd(); + + // Updates the default tags. + // This is thread-safe. + void SetTags(const std::initializer_list& tags); + + // Get the default instance of LogState. + static LogState& Default(); + + private: + std::mutex mutex_; + fidl::ClientEnd<::fuchsia_logger::LogSink> client_end_; + zx::socket socket_; + std::shared_ptr> tags_; +}; + +} // namespace fml + +#endif // FLUTTER_FML_PLATFORM_FUCHSIA_LOG_CONNECTION_H_ diff --git a/engine/src/flutter/shell/platform/fuchsia/dart_runner/main.cc b/engine/src/flutter/shell/platform/fuchsia/dart_runner/main.cc index 33270bc056..15b7fe889c 100644 --- a/engine/src/flutter/shell/platform/fuchsia/dart_runner/main.cc +++ b/engine/src/flutter/shell/platform/fuchsia/dart_runner/main.cc @@ -5,12 +5,13 @@ #include #include #include -#include #include #include #include "dart_runner.h" #include "flutter/fml/logging.h" +#include "flutter/fml/platform/fuchsia/log_interest_listener.h" +#include "flutter/fml/platform/fuchsia/log_state.h" #include "flutter/fml/trace_event.h" #include "logging.h" #include "platform/utils.h" @@ -37,6 +38,12 @@ static void RegisterProfilerSymbols(const char* symbols_path, int main(int argc, const char** argv) { async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread); + // Setup logging. + fml::LogState::Default().SetTags({LOG_TAG}); + fml::LogInterestListener listener(fml::LogState::Default().TakeClientEnd(), + loop.dispatcher()); + listener.AsyncWaitForInterestChanged(); + // Create our component context which is served later. auto context = sys::ComponentContext::Create(); dart_utils::RootInspectNode::Initialize(context.get()); diff --git a/engine/src/flutter/shell/platform/fuchsia/flutter/main.cc b/engine/src/flutter/shell/platform/fuchsia/flutter/main.cc index a8830504d6..bf67e1c5eb 100644 --- a/engine/src/flutter/shell/platform/fuchsia/flutter/main.cc +++ b/engine/src/flutter/shell/platform/fuchsia/flutter/main.cc @@ -10,7 +10,10 @@ #include #include "fml/message_loop.h" +#include "fml/platform/fuchsia/log_interest_listener.h" +#include "fml/platform/fuchsia/log_state.h" #include "lib/async/default.h" +#include "logging.h" #include "platform/utils.h" #include "runner.h" #include "runtime/dart/utils/build_info.h" @@ -20,6 +23,12 @@ int main(int argc, char const* argv[]) { fml::MessageLoop::EnsureInitializedForCurrentThread(); + // Setup logging. + fml::LogState::Default().SetTags({LOG_TAG}); + fml::LogInterestListener listener(fml::LogState::Default().TakeClientEnd(), + async_get_default_dispatcher()); + listener.AsyncWaitForInterestChanged(); + // Create our component context which is served later. auto context = sys::ComponentContext::Create(); dart_utils::RootInspectNode::Initialize(context.get()); diff --git a/engine/src/flutter/testing/fuchsia/meta/test_suite.cml b/engine/src/flutter/testing/fuchsia/meta/test_suite.cml index b1e5f3cf76..39bcd4ad6f 100644 --- a/engine/src/flutter/testing/fuchsia/meta/test_suite.cml +++ b/engine/src/flutter/testing/fuchsia/meta/test_suite.cml @@ -1,4 +1,7 @@ { + include: [ + "sys/component/realm_builder_absolute.shard.cml", + ], facets: { // shell_unittests and embedder_unittests require vulkan to function. "fuchsia.test": { type: "vulkan" }, diff --git a/engine/src/flutter/tools/fuchsia/fuchsia_libs.gni b/engine/src/flutter/tools/fuchsia/fuchsia_libs.gni index 76301e67f2..60fb4c0ade 100644 --- a/engine/src/flutter/tools/fuchsia/fuchsia_libs.gni +++ b/engine/src/flutter/tools/fuchsia/fuchsia_libs.gni @@ -40,14 +40,6 @@ common_libs = [ name = "libfdio.so" path = rebase_path("$fuchsia_sdk_dist") }, - { - name = "libsyslog.so" - path = rebase_path("$fuchsia_sdk_dist") - }, - { - name = "libbackend_fuchsia_globals.so" - path = rebase_path("$fuchsia_sdk_dist") - }, { name = "libvulkan.so" path = rebase_path("$fuchsia_sdk_dist")