diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-12 14:27:29 +0200 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2020-10-13 09:35:20 +0000 |
commit | c30a6232df03e1efbd9f3b226777b07e087a1122 (patch) | |
tree | e992f45784689f373bcc38d1b79a239ebe17ee23 /chromium/fuchsia/base | |
parent | 7b5b123ac58f58ffde0f4f6e488bcd09aa4decd3 (diff) | |
download | qtwebengine-chromium-85-based.tar.gz |
BASELINE: Update Chromium to 85.0.4183.14085-based
Change-Id: Iaa42f4680837c57725b1344f108c0196741f6057
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/fuchsia/base')
19 files changed, 425 insertions, 61 deletions
diff --git a/chromium/fuchsia/base/BUILD.gn b/chromium/fuchsia/base/BUILD.gn index 2dba9680aad..4e0d73dd164 100644 --- a/chromium/fuchsia/base/BUILD.gn +++ b/chromium/fuchsia/base/BUILD.gn @@ -4,30 +4,37 @@ assert(is_fuchsia) -import("//build/buildflag_header.gni") import("//build/config/fuchsia/generate_runner_scripts.gni") -import("//fuchsia/release_channel.gni") import("//testing/test.gni") # Integration helpers for commonly used fuchsia.* APIs. source_set("base") { sources = [ "config_reader.cc", + "feedback_registration.cc", "fuchsia_dir_scheme.cc", "init_logging.cc", + "inspect.cc", "mem_buffer_util.cc", "string_util.cc", ] public = [ "config_reader.h", + "feedback_registration.h", "fuchsia_dir_scheme.h", "init_logging.h", + "inspect.h", "mem_buffer_util.h", "string_util.h", ] deps = [ "//base", + "//components/version_info", + "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.feedback", "//third_party/fuchsia-sdk/sdk/fidl/fuchsia.mem", + "//third_party/fuchsia-sdk/sdk/pkg/fdio", + "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp", + "//third_party/fuchsia-sdk/sdk/pkg/sys_inspect_cpp", "//url", ] } @@ -78,13 +85,6 @@ source_set("legacymetrics") { friend = [ ":*" ] } -# Used to propagate release-qualified package names to integration test code. -buildflag_header("release_channel_buildflags") { - header = "release_channel.h" - flags = [ "FUCHSIA_RELEASE_CHANNEL_SUFFIX=\"$release_channel_suffix\"" ] - visibility = [ "//fuchsia/*" ] -} - source_set("test_support") { testonly = true sources = [ @@ -106,7 +106,6 @@ source_set("test_support") { public_deps = [ ":base", ":modular", - ":release_channel_buildflags", "//base", "//net", "//net:test_support", @@ -120,6 +119,7 @@ source_set("test_support") { test("cr_fuchsia_base_unittests") { sources = [ "agent_impl_unittests.cc", + "inspect_unittest.cc", "legacymetrics_client_unittest.cc", "legacymetrics_histogram_flattener_unittest.cc", "legacymetrics_user_event_recorder_unittest.cc", @@ -132,6 +132,9 @@ test("cr_fuchsia_base_unittests") { "//base:testfidl", "//base/test:run_all_unittests", "//base/test:test_support", + "//components/version_info", "//testing/gtest", + "//third_party/fuchsia-sdk/sdk/pkg/sys_cpp", + "//third_party/fuchsia-sdk/sdk/pkg/sys_inspect_cpp", ] } diff --git a/chromium/fuchsia/base/DEPS b/chromium/fuchsia/base/DEPS index 9455f2ca503..5ded5f1b3d8 100644 --- a/chromium/fuchsia/base/DEPS +++ b/chromium/fuchsia/base/DEPS @@ -1,4 +1,5 @@ include_rules = [ + "+components/version_info", "+mojo/public", "+third_party/blink/public/common/messaging", "+third_party/blink/public/mojom/messaging", diff --git a/chromium/fuchsia/base/agent_impl.cc b/chromium/fuchsia/base/agent_impl.cc index b692599f2a2..4ecd277425e 100644 --- a/chromium/fuchsia/base/agent_impl.cc +++ b/chromium/fuchsia/base/agent_impl.cc @@ -7,7 +7,6 @@ #include <lib/sys/cpp/component_context.h> #include "base/bind.h" -#include "base/fuchsia/default_context.h" namespace cr_fuchsia { diff --git a/chromium/fuchsia/base/agent_impl.h b/chromium/fuchsia/base/agent_impl.h index b630dc8bb6c..389efb30b28 100644 --- a/chromium/fuchsia/base/agent_impl.h +++ b/chromium/fuchsia/base/agent_impl.h @@ -15,7 +15,6 @@ #include "base/bind.h" #include "base/containers/flat_map.h" -#include "base/fuchsia/default_context.h" #include "base/fuchsia/scoped_service_binding.h" #include "base/fuchsia/service_provider_impl.h" #include "base/macros.h" diff --git a/chromium/fuchsia/base/agent_manager.h b/chromium/fuchsia/base/agent_manager.h index 7f60750e471..17fd60c254c 100644 --- a/chromium/fuchsia/base/agent_manager.h +++ b/chromium/fuchsia/base/agent_manager.h @@ -10,7 +10,6 @@ #include <lib/sys/cpp/component_context.h> #include "base/containers/flat_map.h" -#include "base/fuchsia/default_context.h" #include "base/macros.h" #include "base/strings/string_piece.h" diff --git a/chromium/fuchsia/base/config_reader.cc b/chromium/fuchsia/base/config_reader.cc index 87eaab8e48c..0c73357e93a 100644 --- a/chromium/fuchsia/base/config_reader.cc +++ b/chromium/fuchsia/base/config_reader.cc @@ -29,14 +29,14 @@ base::Optional<base::Value> ReadPackageConfig() { return base::nullopt; } - base::JSONReader reader; - base::Optional<base::Value> parsed = reader.Read(file_content); - CHECK(parsed) << "Failed to parse " << path.value() << ": " - << reader.GetErrorMessage(); - CHECK(parsed->is_dict()) << "Config is not a JSON dictinary: " - << path.value(); - - return std::move(parsed.value()); + base::JSONReader::ValueWithError parsed = + base::JSONReader::ReadAndReturnValueWithError(file_content); + CHECK(parsed.value) << "Failed to parse " << path.value() << ": " + << parsed.error_message; + CHECK(parsed.value->is_dict()) + << "Config is not a JSON dictionary: " << path.value(); + + return std::move(parsed.value); } } // namespace diff --git a/chromium/fuchsia/base/context_provider_test_connector.cc b/chromium/fuchsia/base/context_provider_test_connector.cc index ba5f1234432..307f0bd9d0f 100644 --- a/chromium/fuchsia/base/context_provider_test_connector.cc +++ b/chromium/fuchsia/base/context_provider_test_connector.cc @@ -12,10 +12,8 @@ #include <zircon/processargs.h> #include <utility> -#include "base/fuchsia/default_context.h" #include "base/fuchsia/fuchsia_logging.h" -#include "base/strings/strcat.h" -#include "fuchsia/base/release_channel.h" +#include "base/fuchsia/process_context.h" namespace cr_fuchsia { @@ -24,9 +22,8 @@ fidl::InterfaceHandle<fuchsia::io::Directory> StartWebEngineForTests( component_controller_request, const base::CommandLine& command_line) { fuchsia::sys::LaunchInfo launch_info; - launch_info.url = base::StrCat({"fuchsia-pkg://fuchsia.com/web_engine", - BUILDFLAG(FUCHSIA_RELEASE_CHANNEL_SUFFIX), - "#meta/context_provider.cmx"}); + launch_info.url = + "fuchsia-pkg://fuchsia.com/web_engine#meta/context_provider.cmx"; launch_info.arguments = command_line.argv(); // Clone stderr from the current process to WebEngine and ask it to @@ -43,8 +40,7 @@ fidl::InterfaceHandle<fuchsia::io::Directory> StartWebEngineForTests( web_engine_services_dir.NewRequest().TakeChannel(); fuchsia::sys::LauncherPtr launcher; - base::fuchsia::ComponentContextForCurrentProcess()->svc()->Connect( - launcher.NewRequest()); + base::ComponentContextForProcess()->svc()->Connect(launcher.NewRequest()); launcher->CreateComponent(std::move(launch_info), std::move(component_controller_request)); diff --git a/chromium/fuchsia/base/context_provider_test_connector.h b/chromium/fuchsia/base/context_provider_test_connector.h index 0d5ca1fd707..5c4604b25bc 100644 --- a/chromium/fuchsia/base/context_provider_test_connector.h +++ b/chromium/fuchsia/base/context_provider_test_connector.h @@ -20,7 +20,6 @@ fidl::InterfaceHandle<fuchsia::io::Directory> StartWebEngineForTests( const base::CommandLine& command_line = base::CommandLine(base::CommandLine::NO_PROGRAM)); -// TODO(crbug.com/1046615): Use test manifests for package specification. fuchsia::web::ContextProviderPtr ConnectContextProvider( fidl::InterfaceRequest<fuchsia::sys::ComponentController> component_controller_request, diff --git a/chromium/fuchsia/base/feedback_registration.cc b/chromium/fuchsia/base/feedback_registration.cc new file mode 100644 index 00000000000..d8bee5ff647 --- /dev/null +++ b/chromium/fuchsia/base/feedback_registration.cc @@ -0,0 +1,30 @@ +// Copyright 2020 The Chromium 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 "fuchsia/base/feedback_registration.h" + +#include <fuchsia/feedback/cpp/fidl.h> +#include <lib/sys/cpp/component_context.h> + +#include "base/fuchsia/process_context.h" +#include "base/strings/string_piece.h" +#include "components/version_info/version_info.h" + +namespace cr_fuchsia { + +void RegisterCrashReportingFields(base::StringPiece component_url, + base::StringPiece crash_product_name) { + fuchsia::feedback::CrashReportingProduct product_data; + product_data.set_name(crash_product_name.as_string()); + product_data.set_version(version_info::GetVersionNumber()); + // TODO(https://crbug.com/1077428): Use the actual channel when appropriate. + // For now, always set it to the empty string to avoid reporting "missing". + product_data.set_channel(""); + base::ComponentContextForProcess() + ->svc() + ->Connect<fuchsia::feedback::CrashReportingProductRegister>() + ->Upsert(component_url.as_string(), std::move(product_data)); +} + +} // namespace cr_fuchsia diff --git a/chromium/fuchsia/base/feedback_registration.h b/chromium/fuchsia/base/feedback_registration.h new file mode 100644 index 00000000000..7e983bf6a70 --- /dev/null +++ b/chromium/fuchsia/base/feedback_registration.h @@ -0,0 +1,22 @@ +// Copyright 2020 The Chromium 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 FUCHSIA_BASE_FEEDBACK_REGISTRATION_H_ +#define FUCHSIA_BASE_FEEDBACK_REGISTRATION_H_ + +#include "base/strings/string_piece_forward.h" + +namespace cr_fuchsia { + +// Overrides the default Fuchsia product info in crash reports. +// Crashes for the component |component_url| will contain |crash_product_name|, +// the version from version_info, and an appropriate value for the release +// channel. |component_url| must match the current component. The calling +// process must have access to "fuchsia.feedback.CrashReportingProductRegister". +void RegisterCrashReportingFields(base::StringPiece component_url, + base::StringPiece crash_product_name); + +} // namespace cr_fuchsia + +#endif // FUCHSIA_BASE_FEEDBACK_REGISTRATION_H_
\ No newline at end of file diff --git a/chromium/fuchsia/base/frame_test_util.cc b/chromium/fuchsia/base/frame_test_util.cc index c234b3a97fd..2150cd86360 100644 --- a/chromium/fuchsia/base/frame_test_util.cc +++ b/chromium/fuchsia/base/frame_test_util.cc @@ -54,4 +54,19 @@ fuchsia::web::LoadUrlParams CreateLoadUrlParamsWithUserActivation() { return load_url_params; } +fuchsia::web::WebMessage CreateWebMessageWithMessagePortRequest( + fidl::InterfaceRequest<fuchsia::web::MessagePort> message_port_request, + fuchsia::mem::Buffer buffer) { + fuchsia::web::OutgoingTransferable outgoing; + outgoing.set_message_port(std::move(message_port_request)); + + std::vector<fuchsia::web::OutgoingTransferable> outgoing_vector; + outgoing_vector.push_back(std::move(outgoing)); + + fuchsia::web::WebMessage web_message; + web_message.set_outgoing_transfer(std::move(outgoing_vector)); + web_message.set_data(std::move(buffer)); + return web_message; +} + } // namespace cr_fuchsia diff --git a/chromium/fuchsia/base/frame_test_util.h b/chromium/fuchsia/base/frame_test_util.h index 2c2ee036456..20534eaf5e9 100644 --- a/chromium/fuchsia/base/frame_test_util.h +++ b/chromium/fuchsia/base/frame_test_util.h @@ -31,6 +31,12 @@ base::Optional<base::Value> ExecuteJavaScript(fuchsia::web::Frame* frame, // autoplay to be used, which is used by many media tests. fuchsia::web::LoadUrlParams CreateLoadUrlParamsWithUserActivation(); +// Creates a WebMessage with one outgoing transferable set to +// |message_port_request| and data set to |buffer|. +fuchsia::web::WebMessage CreateWebMessageWithMessagePortRequest( + fidl::InterfaceRequest<fuchsia::web::MessagePort> message_port_request, + fuchsia::mem::Buffer buffer); + } // namespace cr_fuchsia #endif // FUCHSIA_BASE_FRAME_TEST_UTIL_H_ diff --git a/chromium/fuchsia/base/inspect.cc b/chromium/fuchsia/base/inspect.cc new file mode 100644 index 00000000000..775ae986618 --- /dev/null +++ b/chromium/fuchsia/base/inspect.cc @@ -0,0 +1,28 @@ +// Copyright 2020 The Chromium 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 "fuchsia/base/inspect.h" + +#include <lib/sys/inspect/cpp/component.h> + +#include "components/version_info/version_info.h" + +namespace cr_fuchsia { + +namespace { +const char kVersion[] = "version"; +const char kLastChange[] = "last_change_revision"; +} // namespace + +void PublishVersionInfoToInspect(sys::ComponentInspector* inspector) { + // These values are managed by the inspector, since they won't be updated over + // the lifetime of the component. + // TODO(https://crbug.com/1077428): Add release channel. + inspector->root().CreateString(kVersion, version_info::GetVersionNumber(), + inspector); + inspector->root().CreateString(kLastChange, version_info::GetLastChange(), + inspector); +} + +} // namespace cr_fuchsia diff --git a/chromium/fuchsia/base/inspect.h b/chromium/fuchsia/base/inspect.h new file mode 100644 index 00000000000..4d8d35335ee --- /dev/null +++ b/chromium/fuchsia/base/inspect.h @@ -0,0 +1,20 @@ +// Copyright 2020 The Chromium 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 FUCHSIA_BASE_INSPECT_H_ +#define FUCHSIA_BASE_INSPECT_H_ + +namespace sys { +class ComponentInspector; +} // namespace sys + +namespace cr_fuchsia { + +// Publish the Chromium version via the Inspect API. The lifetime of +// |inspector| has to be the same as the component it belongs to. +void PublishVersionInfoToInspect(sys::ComponentInspector* inspector); + +} // namespace cr_fuchsia + +#endif // FUCHSIA_BASE_INSPECT_H_
\ No newline at end of file diff --git a/chromium/fuchsia/base/inspect_unittest.cc b/chromium/fuchsia/base/inspect_unittest.cc new file mode 100644 index 00000000000..7a2bff50c81 --- /dev/null +++ b/chromium/fuchsia/base/inspect_unittest.cc @@ -0,0 +1,95 @@ +// Copyright 2020 The Chromium 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 "fuchsia/base/inspect.h" + +#include <lib/fdio/directory.h> +#include <lib/inspect/cpp/hierarchy.h> +#include <lib/inspect/cpp/reader.h> +#include <lib/inspect/service/cpp/reader.h> +#include <lib/sys/cpp/component_context.h> +#include <lib/sys/inspect/cpp/component.h> +#include <cstdint> +#include <memory> + +#include "base/task/single_thread_task_executor.h" +#include "base/test/task_environment.h" +#include "components/version_info/version_info.h" +#include "fuchsia/base/mem_buffer_util.h" +#include "fuchsia/base/string_util.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cr_fuchsia { + +namespace { + +const char kVersion[] = "version"; +const char kLastChange[] = "last_change_revision"; + +class InspectTest : public ::testing::Test { + public: + InspectTest() { + fidl::InterfaceHandle<fuchsia::io::Directory> incoming_directory; + auto incoming_services = + std::make_shared<sys::ServiceDirectory>(std::move(incoming_directory)); + context_ = std::make_unique<sys::ComponentContext>( + std::move(incoming_services), + published_root_directory_.NewRequest().TakeChannel()); + inspector_ = std::make_unique<sys::ComponentInspector>(context_.get()); + base::RunLoop().RunUntilIdle(); + } + + InspectTest(const InspectTest&) = delete; + InspectTest& operator=(const InspectTest&) = delete; + + protected: + base::test::SingleThreadTaskEnvironment task_environment_{ + base::test::SingleThreadTaskEnvironment::MainThreadType::IO}; + std::unique_ptr<sys::ComponentContext> context_; + fidl::InterfaceHandle<fuchsia::io::Directory> published_root_directory_; + std::unique_ptr<sys::ComponentInspector> inspector_; +}; + +} // namespace + +TEST_F(InspectTest, PublishVersionInfoToInspect) { + cr_fuchsia::PublishVersionInfoToInspect(inspector_.get()); + fidl::InterfaceHandle<fuchsia::io::Directory> directory; + zx_status_t status = fdio_service_connect_at( + published_root_directory_.channel().get(), "diagnostics", + directory.NewRequest().TakeChannel().release()); + ASSERT_EQ(ZX_OK, status); + std::unique_ptr<sys::ServiceDirectory> diagnostics = + std::make_unique<sys::ServiceDirectory>(std::move(directory)); + + // Access the inspect::Tree where the data is served. |tree| is in the + // directory created for the test, not the diagnostics directory for the test + // component. + fuchsia::inspect::TreePtr tree; + diagnostics->Connect(tree.NewRequest()); + fuchsia::inspect::TreeContent content; + base::RunLoop run_loop; + tree->GetContent([&content, &run_loop](fuchsia::inspect::TreeContent c) { + content = std::move(c); + run_loop.Quit(); + }); + run_loop.Run(); + + // Parse the data as an inspect::Hierarchy. + ASSERT_TRUE(content.has_buffer()); + std::string buffer_data; + cr_fuchsia::StringFromMemBuffer(content.buffer(), &buffer_data); + inspect::Hierarchy hierarchy = + inspect::ReadFromBuffer(cr_fuchsia::StringToBytes(buffer_data)) + .take_value(); + + auto* property = + hierarchy.node().get_property<inspect::StringPropertyValue>(kVersion); + EXPECT_EQ(property->value(), version_info::GetVersionNumber()); + property = + hierarchy.node().get_property<inspect::StringPropertyValue>(kLastChange); + EXPECT_EQ(property->value(), version_info::GetLastChange()); +} + +} // namespace cr_fuchsia diff --git a/chromium/fuchsia/base/legacymetrics_client.cc b/chromium/fuchsia/base/legacymetrics_client.cc index a2d45a83ac8..58f384124c1 100644 --- a/chromium/fuchsia/base/legacymetrics_client.cc +++ b/chromium/fuchsia/base/legacymetrics_client.cc @@ -11,8 +11,8 @@ #include <utility> #include <vector> -#include "base/fuchsia/default_context.h" #include "base/fuchsia/fuchsia_logging.h" +#include "base/fuchsia/process_context.h" #include "base/logging.h" #include "base/threading/thread_task_runner_handle.h" #include "base/time/time.h" @@ -34,11 +34,13 @@ void LegacyMetricsClient::Start(base::TimeDelta report_interval) { DCHECK(!metrics_recorder_) << "Start() called more than once."; report_interval_ = report_interval; - metrics_recorder_ = base::fuchsia::ComponentContextForCurrentProcess() + metrics_recorder_ = base::ComponentContextForProcess() ->svc() ->Connect<fuchsia::legacymetrics::MetricsRecorder>(); metrics_recorder_.set_error_handler(fit::bind_member( this, &LegacyMetricsClient::OnMetricsRecorderDisconnected)); + metrics_recorder_.events().OnCloseSoon = + fit::bind_member(this, &LegacyMetricsClient::OnCloseSoon); user_events_recorder_ = std::make_unique<LegacyMetricsUserActionRecorder>(); ScheduleNextReport(); } @@ -54,7 +56,18 @@ void LegacyMetricsClient::SetReportAdditionalMetricsCallback( report_additional_callback_ = std::move(callback); } +void LegacyMetricsClient::SetNotifyFlushCallback(NotifyFlushCallback callback) { + DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); + DCHECK(callback); + DCHECK(!metrics_recorder_) + << "SetNotifyFlushCallback() must be called before Start()."; + + notify_flush_callback_ = std::move(callback); +} + void LegacyMetricsClient::ScheduleNextReport() { + DCHECK(!is_flushing_); + DVLOG(1) << "Scheduling next report in " << report_interval_.InSeconds() << "seconds."; timer_.Start(FROM_HERE, report_interval_, this, @@ -91,44 +104,70 @@ void LegacyMetricsClient::Report( } } - if (events.empty()) { - ScheduleNextReport(); - return; - } + std::move(events.begin(), events.end(), std::back_inserter(to_send_)); - DrainBuffer(std::move(events)); + DrainBuffer(); } -void LegacyMetricsClient::DrainBuffer( - std::vector<fuchsia::legacymetrics::Event> buffer) { - if (buffer.empty()) { +void LegacyMetricsClient::DrainBuffer() { + DVLOG(1) << __func__ << " called."; + + if (record_ack_pending_) { + // There is a Record() call already inflight. When it is acknowledged, + // buffer draining will continue. + return; + } + + if (to_send_.empty()) { DVLOG(1) << "Buffer drained."; - ScheduleNextReport(); + + if (is_flushing_) { + metrics_recorder_.Unbind(); + } else { + ScheduleNextReport(); + } + return; } - // Since ordering doesn't matter, we can efficiently drain |buffer| by + // Since ordering doesn't matter, we can efficiently drain |to_send_| by // repeatedly sending and truncating its tail. - const size_t batch_size = std::min(buffer.size(), kMaxBatchSize); - const size_t batch_start_idx = buffer.size() - batch_size; + const size_t batch_size = std::min(to_send_.size(), kMaxBatchSize); + const size_t batch_start_idx = to_send_.size() - batch_size; std::vector<fuchsia::legacymetrics::Event> batch; batch.resize(batch_size); - std::move(buffer.begin() + batch_start_idx, buffer.end(), batch.begin()); - buffer.resize(buffer.size() - batch_size); - - metrics_recorder_->Record(std::move(batch), - [this, buffer = std::move(buffer)]() mutable { - DrainBuffer(std::move(buffer)); - }); + std::move(to_send_.begin() + batch_start_idx, to_send_.end(), batch.begin()); + to_send_.resize(to_send_.size() - batch_size); + + record_ack_pending_ = true; + metrics_recorder_->Record(std::move(batch), [this]() { + record_ack_pending_ = false; + DrainBuffer(); + }); } void LegacyMetricsClient::OnMetricsRecorderDisconnected(zx_status_t status) { - ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status) - << "MetricsRecorder connection lost."; + ZX_LOG(ERROR, status) << "MetricsRecorder connection lost."; // Stop recording & reporting user events. user_events_recorder_.reset(); timer_.AbandonAndStop(); } +void LegacyMetricsClient::OnCloseSoon() { + DVLOG(1) << __func__ << " called."; + + timer_.AbandonAndStop(); + + is_flushing_ = true; + if (notify_flush_callback_) { + // Defer reporting until the flush operation has finished. + std::move(notify_flush_callback_) + .Run(base::BindOnce(&LegacyMetricsClient::StartReport, + weak_factory_.GetWeakPtr())); + } else { + StartReport(); + } +} + } // namespace cr_fuchsia diff --git a/chromium/fuchsia/base/legacymetrics_client.h b/chromium/fuchsia/base/legacymetrics_client.h index 98576a1f410..b9ec76a2a1f 100644 --- a/chromium/fuchsia/base/legacymetrics_client.h +++ b/chromium/fuchsia/base/legacymetrics_client.h @@ -31,6 +31,8 @@ class LegacyMetricsClient { using ReportAdditionalMetricsCallback = base::RepeatingCallback<void( base::OnceCallback<void(std::vector<fuchsia::legacymetrics::Event>)>)>; + using NotifyFlushCallback = + base::OnceCallback<void(base::OnceClosure completion_cb)>; LegacyMetricsClient(); ~LegacyMetricsClient(); @@ -50,18 +52,27 @@ class LegacyMetricsClient { void SetReportAdditionalMetricsCallback( ReportAdditionalMetricsCallback callback); + // Sets a |callback| which is invoked to warn that the connection to the + // remote MetricsRecorder will be terminated. The completion closure passed to + // |callback| should be invoked to signal flush completion. + void SetNotifyFlushCallback(NotifyFlushCallback callback); + private: void ScheduleNextReport(); void StartReport(); void Report(std::vector<fuchsia::legacymetrics::Event> additional_metrics); void OnMetricsRecorderDisconnected(zx_status_t status); + void OnCloseSoon(); - // Incrementally sends the contents of |buffer| to |metrics_recorder|, and - // invokes |done_cb| when finished. - void DrainBuffer(std::vector<fuchsia::legacymetrics::Event> buffer); + // Incrementally sends the contents of |to_send_| to |metrics_recorder_|. + void DrainBuffer(); base::TimeDelta report_interval_; ReportAdditionalMetricsCallback report_additional_callback_; + NotifyFlushCallback notify_flush_callback_; + bool is_flushing_ = false; + bool record_ack_pending_ = false; + std::vector<fuchsia::legacymetrics::Event> to_send_; std::unique_ptr<LegacyMetricsUserActionRecorder> user_events_recorder_; fuchsia::legacymetrics::MetricsRecorderPtr metrics_recorder_; diff --git a/chromium/fuchsia/base/legacymetrics_client_unittest.cc b/chromium/fuchsia/base/legacymetrics_client_unittest.cc index 8c735bbbffe..1b48827418a 100644 --- a/chromium/fuchsia/base/legacymetrics_client_unittest.cc +++ b/chromium/fuchsia/base/legacymetrics_client_unittest.cc @@ -14,6 +14,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "fuchsia/base/legacymetrics_client.h" #include "fuchsia/base/legacymetrics_histogram_flattener.h" +#include "fuchsia/base/result_receiver.h" #include "testing/gtest/include/gtest/gtest.h" namespace cr_fuchsia { @@ -45,10 +46,21 @@ class TestMetricsRecorder ack_callback_ = base::nullopt; } + void set_expect_ack_dropped(bool expect_dropped) { + expect_ack_dropped_ = expect_dropped; + } + // fuchsia::legacymetrics::MetricsRecorder implementation. void Record(std::vector<fuchsia::legacymetrics::Event> events, RecordCallback callback) override { - recorded_events_ = std::move(events); + std::move(events.begin(), events.end(), + std::back_inserter(recorded_events_)); + + // Received a call to Record() before the previous one was acknowledged, + // which can happen in some cases (e.g. flushing). + if (ack_callback_) + EXPECT_TRUE(expect_ack_dropped_); + ack_callback_ = std::move(callback); if (on_record_cb_) @@ -61,6 +73,7 @@ class TestMetricsRecorder std::vector<fuchsia::legacymetrics::Event> recorded_events_; base::OnceClosure on_record_cb_; base::Optional<RecordCallback> ack_callback_; + bool expect_ack_dropped_ = false; }; class LegacyMetricsClientTest : public testing::Test { @@ -71,9 +84,10 @@ class LegacyMetricsClientTest : public testing::Test { ~LegacyMetricsClientTest() override = default; void SetUp() override { - service_binding_ = std::make_unique<base::fuchsia::ScopedServiceBinding< - fuchsia::legacymetrics::MetricsRecorder>>( - test_context_.additional_services(), &test_recorder_); + service_binding_ = + std::make_unique<base::fuchsia::ScopedSingleClientServiceBinding< + fuchsia::legacymetrics::MetricsRecorder>>( + test_context_.additional_services(), &test_recorder_); base::SetRecordActionTaskRunner(base::ThreadTaskRunnerHandle::Get()); // Flush any dirty histograms from previous test runs in this process. @@ -84,7 +98,7 @@ class LegacyMetricsClientTest : public testing::Test { base::test::TaskEnvironment task_environment_; base::TestComponentContextForProcess test_context_; TestMetricsRecorder test_recorder_; - std::unique_ptr<base::fuchsia::ScopedServiceBinding< + std::unique_ptr<base::fuchsia::ScopedSingleClientServiceBinding< fuchsia::legacymetrics::MetricsRecorder>> service_binding_; LegacyMetricsClient client_; @@ -216,5 +230,92 @@ TEST_F(LegacyMetricsClientTest, Batching) { test_recorder_.SendAck(); } +TEST_F(LegacyMetricsClientTest, FlushWithPending) { + client_.Start(kReportInterval); + base::RunLoop().RunUntilIdle(); + + UMA_HISTOGRAM_COUNTS_1M("foo", 20); + + EXPECT_FALSE(test_recorder_.IsRecordInFlight()); + service_binding_->events().OnCloseSoon(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(test_recorder_.IsRecordInFlight()); + + // The service should be unbound once all data is drained. + EXPECT_TRUE(service_binding_->has_clients()); + auto events = test_recorder_.WaitForEvents(); + test_recorder_.SendAck(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(1u, events.size()); + EXPECT_EQ("foo", events[0].histogram().name()); + EXPECT_FALSE(service_binding_->has_clients()); +} + +TEST_F(LegacyMetricsClientTest, FlushNoData) { + client_.Start(kReportInterval); + base::RunLoop().RunUntilIdle(); + + EXPECT_TRUE(service_binding_->has_clients()); + EXPECT_FALSE(test_recorder_.IsRecordInFlight()); + service_binding_->events().OnCloseSoon(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(service_binding_->has_clients()); +} + +TEST_F(LegacyMetricsClientTest, FlushWithOutstandingAck) { + client_.Start(kReportInterval); + base::RunLoop().RunUntilIdle(); + + // Send "foo", but don't ack. + UMA_HISTOGRAM_COUNTS_1M("foo", 20); + task_environment_.FastForwardBy(kReportInterval); + EXPECT_TRUE(test_recorder_.IsRecordInFlight()); + + // Allow the flush operation to call Record() without waiting for a prior ack. + test_recorder_.set_expect_ack_dropped(true); + + // Buffer another event and trigger a flush. + UMA_HISTOGRAM_COUNTS_1M("bar", 20); + EXPECT_TRUE(service_binding_->has_clients()); + service_binding_->events().OnCloseSoon(); + + // Simulate an asynchronous ack from the recorder, which be delivered around + // the same time as the flush's Record() call. The ack should be gracefully + // ignored by the client. + test_recorder_.SendAck(); + + base::RunLoop().RunUntilIdle(); + + auto events = test_recorder_.WaitForEvents(); + test_recorder_.SendAck(); + base::RunLoop().RunUntilIdle(); + EXPECT_EQ(2u, events.size()); + EXPECT_EQ("foo", events[0].histogram().name()); + EXPECT_EQ("bar", events[1].histogram().name()); + EXPECT_FALSE(service_binding_->has_clients()); +} + +TEST_F(LegacyMetricsClientTest, ExternalFlushSignal) { + ResultReceiver<base::OnceClosure> flush_receiver; + client_.SetNotifyFlushCallback(flush_receiver.GetReceiveCallback()); + client_.Start(kReportInterval); + base::RunLoop().RunUntilIdle(); + + UMA_HISTOGRAM_COUNTS_1M("foo", 20); + + // Verify that reporting does not start until the flush completion callback is + // run. + EXPECT_FALSE(test_recorder_.IsRecordInFlight()); + service_binding_->events().OnCloseSoon(); + base::RunLoop().RunUntilIdle(); + EXPECT_FALSE(test_recorder_.IsRecordInFlight()); + + // Verify that invoking the completion callback unblocks reporting. + EXPECT_TRUE(flush_receiver.has_value()); + std::move(*flush_receiver).Run(); + base::RunLoop().RunUntilIdle(); + EXPECT_TRUE(test_recorder_.IsRecordInFlight()); +} + } // namespace } // namespace cr_fuchsia diff --git a/chromium/fuchsia/base/legacymetrics_histogram_flattener.cc b/chromium/fuchsia/base/legacymetrics_histogram_flattener.cc index e05d87ced9a..b6d728143c1 100644 --- a/chromium/fuchsia/base/legacymetrics_histogram_flattener.cc +++ b/chromium/fuchsia/base/legacymetrics_histogram_flattener.cc @@ -8,6 +8,7 @@ #include <utility> #include <vector> +#include "base/logging.h" #include "base/metrics/statistics_recorder.h" namespace cr_fuchsia { |