aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandroid-build-prod (mdb) <android-build-team-robot@google.com>2020-10-01 20:30:01 +0000
committerandroid-build-prod (mdb) <android-build-team-robot@google.com>2020-10-01 20:30:01 +0000
commit856365b4b8fdbcaee45bd9cac3380f69de84c481 (patch)
treee60b2c1df95885dc9e0c67cf9558b8898b036188
parent38c21bba201db8c6ca0a52935adcfac6dda54636 (diff)
parent49aee802dc56f64c5eb55504bbe88120fafb6f68 (diff)
downloadplatform_external_libbrillo-sdk-release.tar.gz
platform_external_libbrillo-sdk-release.tar.bz2
platform_external_libbrillo-sdk-release.zip
Snap for 6877830 from 49aee802dc56f64c5eb55504bbe88120fafb6f68 to sdk-releasesdk-release
Change-Id: I16701d8f27ec745ac49b6f018c5dc70507ac1781
-rw-r--r--BUILD.gn247
-rw-r--r--OWNERS6
-rw-r--r--brillo/asynchronous_signal_handler.cc90
-rw-r--r--brillo/asynchronous_signal_handler.h38
-rw-r--r--brillo/asynchronous_signal_handler_interface.h3
-rw-r--r--brillo/binder_watcher.cc26
-rw-r--r--brillo/binder_watcher.h10
-rw-r--r--brillo/blkdev_utils/loop_device.cc3
-rw-r--r--brillo/cryptohome.cc2
-rw-r--r--brillo/cryptohome.h3
-rw-r--r--brillo/daemons/daemon.cc3
-rw-r--r--brillo/dbus/data_serialization.cc1
-rw-r--r--brillo/dbus/dbus_method_invoker_test.cc36
-rw-r--r--brillo/dbus/dbus_object.cc4
-rw-r--r--brillo/dbus/dbus_property.h4
-rw-r--r--brillo/dbus/dbus_signal_handler_test.cc5
-rw-r--r--brillo/dbus/exported_object_manager.cc4
-rw-r--r--brillo/file_utils.cc20
-rw-r--r--brillo/file_utils.h42
-rw-r--r--brillo/file_utils_test.cc166
-rw-r--r--brillo/files/file_util_test.cc5
-rw-r--r--brillo/files/safe_fd.cc56
-rw-r--r--brillo/files/safe_fd.h7
-rw-r--r--brillo/files/safe_fd_test.cc71
-rw-r--r--brillo/flag_helper.cc16
-rw-r--r--brillo/flag_helper.h18
-rw-r--r--brillo/flag_helper_test.cc117
-rw-r--r--brillo/http/http_proxy_test.cc33
-rw-r--r--brillo/http/http_transport_curl.cc97
-rw-r--r--brillo/http/http_transport_curl_test.cc3
-rw-r--r--brillo/message_loops/base_message_loop.cc255
-rw-r--r--brillo/message_loops/base_message_loop.h83
-rw-r--r--brillo/message_loops/fake_message_loop.cc64
-rw-r--r--brillo/message_loops/fake_message_loop.h24
-rw-r--r--brillo/message_loops/fake_message_loop_test.cc53
-rw-r--r--brillo/message_loops/message_loop.h43
-rw-r--r--brillo/message_loops/message_loop_test.cc267
-rw-r--r--brillo/message_loops/message_loop_utils.cc11
-rw-r--r--brillo/message_loops/message_loop_utils.h2
-rw-r--r--brillo/message_loops/mock_message_loop.h18
-rw-r--r--brillo/minijail/minijail.cc29
-rw-r--r--brillo/minijail/minijail.h17
-rw-r--r--brillo/minijail/mock_minijail.h24
-rw-r--r--brillo/namespaces/OWNERS2
-rw-r--r--brillo/namespaces/mock_platform.h37
-rw-r--r--brillo/namespaces/mount_namespace.cc114
-rw-r--r--brillo/namespaces/mount_namespace.h70
-rw-r--r--brillo/namespaces/mount_namespace_test.cc92
-rw-r--r--brillo/namespaces/platform.cc75
-rw-r--r--brillo/namespaces/platform.h71
-rw-r--r--brillo/scoped_mount_namespace.cc2
-rw-r--r--brillo/scoped_mount_namespace.h2
-rw-r--r--brillo/secure_allocator.h196
-rw-r--r--brillo/secure_blob_test.cc55
-rw-r--r--brillo/streams/file_stream.cc56
-rw-r--r--brillo/streams/file_stream_test.cc1
-rw-r--r--brillo/streams/input_stream_set.cc2
-rw-r--r--brillo/streams/memory_stream.cc2
-rw-r--r--brillo/streams/stream.cc10
-rw-r--r--brillo/streams/stream_utils.cc2
-rw-r--r--brillo/streams/stream_utils_test.cc5
-rw-r--r--brillo/streams/tls_stream.cc8
-rw-r--r--brillo/timezone/EST_test.tzifbin0 -> 127 bytes
-rw-r--r--brillo/timezone/Indian_Christmas_test.tzifbin0 -> 182 bytes
-rw-r--r--brillo/timezone/Pacific_Fiji_test.tzifbin0 -> 122 bytes
-rw-r--r--brillo/timezone/tzif_parser.cc164
-rw-r--r--brillo/timezone/tzif_parser.h29
-rw-r--r--brillo/timezone/tzif_parser_test.cc46
-rw-r--r--brillo/type_list.h16
-rw-r--r--policy/OWNERS1
-rw-r--r--policy/device_policy_impl.cc3
71 files changed, 1911 insertions, 1176 deletions
diff --git a/BUILD.gn b/BUILD.gn
index f30f945..8eefb58 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -8,17 +8,17 @@ import("//common-mk/proto_library.gni")
group("all") {
deps = [
- ":libbrillo-${libbase_ver}",
- ":libbrillo-glib-${libbase_ver}",
- ":libbrillo-test-${libbase_ver}",
- ":libinstallattributes-${libbase_ver}",
- ":libpolicy-${libbase_ver}",
+ ":libbrillo",
+ ":libbrillo-glib",
+ ":libbrillo-test",
+ ":libinstallattributes",
+ ":libpolicy",
]
if (use.test) {
deps += [
- ":libbrillo-${libbase_ver}_tests",
- ":libinstallattributes-${libbase_ver}_tests",
- ":libpolicy-${libbase_ver}_tests",
+ ":libbrillo_tests",
+ ":libinstallattributes_tests",
+ ":libpolicy_tests",
]
}
if (use.fuzzer) {
@@ -44,7 +44,7 @@ config("target_defaults") {
]
}
-config("libbrillo-${libbase_ver}_configs") {
+config("libbrillo_configs") {
include_dirs = [ "../libbrillo" ]
}
@@ -56,7 +56,7 @@ libbrillo_sublibs = [
# |library_name| is library file name without "lib" prefix. This is needed
# for composing -l*** flags in libbrillo-${libbasever}.so.
# (Current version of GN deployed to ChromeOS doesn't have string_replace.)
- library_name = "brillo-core-${libbase_ver}"
+ library_name = "brillo-core"
if (use.dbus) {
all_dependent_pkg_deps = [ "dbus-1" ]
}
@@ -81,11 +81,11 @@ libbrillo_sublibs = [
"brillo/process.cc",
"brillo/process_information.cc",
"brillo/process_reaper.cc",
- "brillo/scoped_mount_namespace.cc",
"brillo/scoped_umask.cc",
"brillo/secure_blob.cc",
"brillo/strings/string_utils.cc",
"brillo/syslog_logging.cc",
+ "brillo/timezone/tzif_parser.cc",
"brillo/type_name_undecorate.cc",
"brillo/url_utils.cc",
"brillo/userdb_utils.cc",
@@ -112,13 +112,9 @@ libbrillo_sublibs = [
},
{
- library_name = "brillo-blockdeviceutils-${libbase_ver}"
- deps = [
- ":libbrillo-core-${libbase_ver}",
- ]
- sources = [
- "brillo/blkdev_utils/loop_device.cc",
- ]
+ library_name = "brillo-blockdeviceutils"
+ deps = [ ":libbrillo-core" ]
+ sources = [ "brillo/blkdev_utils/loop_device.cc" ]
if (use.device_mapper) {
pkg_deps = [ "devmapper" ]
sources += [
@@ -129,10 +125,10 @@ libbrillo_sublibs = [
},
{
- library_name = "brillo-http-${libbase_ver}"
+ library_name = "brillo-http"
deps = [
- ":libbrillo-core-${libbase_ver}",
- ":libbrillo-streams-${libbase_ver}",
+ ":libbrillo-core",
+ ":libbrillo-streams",
]
all_dependent_pkg_deps = [ "libcurl" ]
sources = [
@@ -150,10 +146,8 @@ libbrillo_sublibs = [
},
{
- library_name = "brillo-streams-${libbase_ver}"
- deps = [
- ":libbrillo-core-${libbase_ver}",
- ]
+ library_name = "brillo-streams"
+ deps = [ ":libbrillo-core" ]
all_dependent_pkg_deps = [ "openssl" ]
sources = [
"brillo/streams/file_stream.cc",
@@ -169,34 +163,38 @@ libbrillo_sublibs = [
},
{
- library_name = "brillo-cryptohome-${libbase_ver}"
+ library_name = "brillo-cryptohome"
all_dependent_pkg_deps = [ "openssl" ]
+ sources = [ "brillo/cryptohome.cc" ]
+ },
+
+ {
+ library_name = "brillo-namespaces"
+ deps = [ ":libbrillo-core" ]
sources = [
- "brillo/cryptohome.cc",
+ "brillo/namespaces/mount_namespace.cc",
+ "brillo/namespaces/platform.cc",
+ "brillo/scoped_mount_namespace.cc",
]
},
{
- library_name = "brillo-minijail-${libbase_ver}"
+ library_name = "brillo-minijail"
all_dependent_pkg_deps = [ "libminijail" ]
- sources = [
- "brillo/minijail/minijail.cc",
- ]
+ sources = [ "brillo/minijail/minijail.cc" ]
},
{
- library_name = "brillo-protobuf-${libbase_ver}"
+ library_name = "brillo-protobuf"
all_dependent_pkg_deps = [ "protobuf" ]
- sources = [
- "brillo/proto_file_io.cc",
- ]
+ sources = [ "brillo/proto_file_io.cc" ]
},
]
if (use.udev) {
libbrillo_sublibs += [
{
- library_name = "brillo-udev-${libbase_ver}"
+ library_name = "brillo-udev"
all_dependent_pkg_deps = [ "libudev" ]
sources = [
"brillo/udev/udev.cc",
@@ -238,7 +236,7 @@ foreach(attr, libbrillo_sublibs) {
}
}
-generate_pkg_config("libbrillo_pc") {
+generate_pkg_config("libbrillo-${libbase_ver}_pc") {
name = "libbrillo"
output_name = "libbrillo-${libbase_ver}"
description = "brillo base library"
@@ -256,20 +254,40 @@ generate_pkg_config("libbrillo_pc") {
}
}
defines = [ "USE_RTTI_FOR_TYPE_TAGS" ]
- libs = [ "-lbrillo-${libbase_ver}" ]
+ libs = [ "-lbrillo" ]
+}
+
+generate_pkg_config("libbrillo_pc") {
+ name = "libbrillo"
+ output_name = "libbrillo"
+ description = "brillo base library"
+ version = libbase_ver
+ requires_private = default_pkg_deps
+ foreach(sublib, libbrillo_sublibs) {
+ if (defined(sublib.pkg_deps)) {
+ requires_private += sublib.pkg_deps
+ }
+ if (defined(sublib.public_pkg_deps)) {
+ requires_private += sublib.public_pkg_deps
+ }
+ if (defined(sublib.all_dependent_pkg_deps)) {
+ requires_private += sublib.all_dependent_pkg_deps
+ }
+ }
+ defines = [ "USE_RTTI_FOR_TYPE_TAGS" ]
+ libs = [ "-lbrillo" ]
}
-action("libbrillo-${libbase_ver}") {
+action("libbrillo") {
deps = [
+ ":libbrillo-${libbase_ver}_pc",
":libbrillo_pc",
]
foreach(sublib, libbrillo_sublibs) {
deps += [ ":lib" + sublib.library_name ]
}
script = "//common-mk/write_args.py"
- outputs = [
- "${root_out_dir}/lib/libbrillo-${libbase_ver}.so",
- ]
+ outputs = [ "${root_out_dir}/lib/libbrillo.so" ]
args = [ "--output" ] + outputs + [ "--" ] + [
"GROUP",
"(",
@@ -285,16 +303,42 @@ action("libbrillo-${libbase_ver}") {
]
}
-libbrillo_test_deps = [ "libbrillo-http-${libbase_ver}" ]
+libbrillo_test_deps = [ "libbrillo-http" ]
-generate_pkg_config("libbrillo-test_pc") {
+generate_pkg_config("libbrillo-test-${libbase_ver}_pc") {
name = "libbrillo-test"
output_name = "libbrillo-test-${libbase_ver}"
description = "brillo test library"
version = libbase_ver
# Because libbrillo-test is static, we have to depend directly on everything.
- requires = [ "libbrillo-${libbase_ver}" ] + default_pkg_deps
+ requires = [ "libbrillo" ] + default_pkg_deps
+ foreach(name, libbrillo_test_deps) {
+ foreach(t, libbrillo_sublibs) {
+ if ("lib" + t.library_name == name) {
+ if (defined(t.pkg_deps)) {
+ requires += t.pkg_deps
+ }
+ if (defined(t.public_pkg_deps)) {
+ requires += t.public_pkg_deps
+ }
+ if (defined(t.all_dependent_pkg_deps)) {
+ requires += t.all_dependent_pkg_deps
+ }
+ }
+ }
+ }
+ libs = [ "-lbrillo-test" ]
+}
+
+generate_pkg_config("libbrillo-test_pc") {
+ name = "libbrillo-test"
+ output_name = "libbrillo-test"
+ description = "brillo test library"
+ version = libbase_ver
+
+ # Because libbrillo-test is static, we have to depend directly on everything.
+ requires = [ "libbrillo" ] + default_pkg_deps
foreach(name, libbrillo_test_deps) {
foreach(t, libbrillo_sublibs) {
if ("lib" + t.library_name == name) {
@@ -310,17 +354,18 @@ generate_pkg_config("libbrillo-test_pc") {
}
}
}
- libs = [ "-lbrillo-test-${libbase_ver}" ]
+ libs = [ "-lbrillo-test" ]
}
-static_library("libbrillo-test-${libbase_ver}") {
+static_library("libbrillo-test") {
configs -= [ "//common-mk:use_thin_archive" ]
configs += [
"//common-mk:nouse_thin_archive",
":target_defaults",
]
deps = [
- ":libbrillo-http-${libbase_ver}",
+ ":libbrillo-http",
+ ":libbrillo-test-${libbase_ver}_pc",
":libbrillo-test_pc",
]
foreach(name, libbrillo_test_deps) {
@@ -339,22 +384,20 @@ static_library("libbrillo-test-${libbase_ver}") {
}
}
-shared_library("libinstallattributes-${libbase_ver}") {
+shared_library("libinstallattributes") {
configs += [ ":target_defaults" ]
deps = [
":libinstallattributes-includes",
"../common-mk/external_dependencies:install_attributes-proto",
]
all_dependent_pkg_deps = [ "protobuf-lite" ]
- sources = [
- "install_attributes/libinstallattributes.cc",
- ]
+ sources = [ "install_attributes/libinstallattributes.cc" ]
}
-shared_library("libpolicy-${libbase_ver}") {
+shared_library("libpolicy") {
configs += [ ":target_defaults" ]
deps = [
- ":libinstallattributes-${libbase_ver}",
+ ":libinstallattributes",
":libpolicy-includes",
"../common-mk/external_dependencies:policy-protos",
]
@@ -383,19 +426,29 @@ if (use.dbus) {
]
}
-generate_pkg_config("libbrillo-glib_pc") {
+generate_pkg_config("libbrillo-glib-${libbase_ver}_pc") {
name = "libbrillo-glib"
output_name = "libbrillo-glib-${libbase_ver}"
description = "brillo glib wrapper library"
version = libbase_ver
requires_private = libbrillo_glib_pkg_deps
- libs = [ "-lbrillo-glib-${libbase_ver}" ]
+ libs = [ "-lbrillo-glib" ]
+}
+
+generate_pkg_config("libbrillo-glib_pc") {
+ name = "libbrillo-glib"
+ output_name = "libbrillo-glib"
+ description = "brillo glib wrapper library"
+ version = libbase_ver
+ requires_private = libbrillo_glib_pkg_deps
+ libs = [ "-lbrillo-glib" ]
}
-shared_library("libbrillo-glib-${libbase_ver}") {
+shared_library("libbrillo-glib") {
configs += [ ":target_defaults" ]
deps = [
- ":libbrillo-${libbase_ver}",
+ ":libbrillo",
+ ":libbrillo-glib-${libbase_ver}_pc",
":libbrillo-glib_pc",
]
all_dependent_pkg_deps = libbrillo_glib_pkg_deps
@@ -412,35 +465,34 @@ shared_library("libbrillo-glib-${libbase_ver}") {
}
if (use.test) {
- static_library("libbrillo-${libbase_ver}_static") {
+ static_library("libbrillo_static") {
configs += [ ":target_defaults" ]
deps = [
+ ":libbrillo-${libbase_ver}_pc",
":libbrillo_pc",
- ":libinstallattributes-${libbase_ver}",
- ":libpolicy-${libbase_ver}",
+ ":libinstallattributes",
+ ":libpolicy",
]
foreach(sublib, libbrillo_sublibs) {
deps += [ ":lib" + sublib.library_name ]
}
- public_configs = [ ":libbrillo-${libbase_ver}_configs" ]
+ public_configs = [ ":libbrillo_configs" ]
}
- proto_library("libbrillo-${libbase_ver}_tests_proto") {
+ proto_library("libbrillo_tests_proto") {
proto_in_dir = "brillo/dbus"
proto_out_dir = "include/brillo/dbus"
- sources = [
- "${proto_in_dir}/test.proto",
- ]
+ sources = [ "${proto_in_dir}/test.proto" ]
}
- executable("libbrillo-${libbase_ver}_tests") {
+ executable("libbrillo_tests") {
configs += [
"//common-mk:test",
":target_defaults",
]
deps = [
- ":libbrillo-${libbase_ver}_static",
- ":libbrillo-${libbase_ver}_tests_proto",
- ":libbrillo-glib-${libbase_ver}",
- ":libbrillo-test-${libbase_ver}",
+ ":libbrillo-glib",
+ ":libbrillo-test",
+ ":libbrillo_static",
+ ":libbrillo_tests_proto",
]
pkg_deps = [ "libchrome-test-${libbase_ver}" ]
cflags = [ "-Wno-format-zero-length" ]
@@ -477,6 +529,7 @@ if (use.test) {
"brillo/message_loops/fake_message_loop_test.cc",
"brillo/message_loops/message_loop_test.cc",
"brillo/mime_utils_test.cc",
+ "brillo/namespaces/mount_namespace_test.cc",
"brillo/osrelease_reader_test.cc",
"brillo/process_reaper_test.cc",
"brillo/process_test.cc",
@@ -491,6 +544,7 @@ if (use.test) {
"brillo/streams/stream_test.cc",
"brillo/streams/stream_utils_test.cc",
"brillo/strings/string_utils_test.cc",
+ "brillo/timezone/tzif_parser_test.cc",
"brillo/unittest_utils.cc",
"brillo/url_utils_test.cc",
"brillo/value_conversion_test.cc",
@@ -519,29 +573,27 @@ if (use.test) {
}
}
- executable("libinstallattributes-${libbase_ver}_tests") {
+ executable("libinstallattributes_tests") {
configs += [
"//common-mk:test",
":target_defaults",
]
deps = [
- ":libinstallattributes-${libbase_ver}",
+ ":libinstallattributes",
"../common-mk/external_dependencies:install_attributes-proto",
"../common-mk/testrunner:testrunner",
]
- sources = [
- "install_attributes/tests/libinstallattributes_test.cc",
- ]
+ sources = [ "install_attributes/tests/libinstallattributes_test.cc" ]
}
- executable("libpolicy-${libbase_ver}_tests") {
+ executable("libpolicy_tests") {
configs += [
"//common-mk:test",
":target_defaults",
]
deps = [
- ":libinstallattributes-${libbase_ver}",
- ":libpolicy-${libbase_ver}",
+ ":libinstallattributes",
+ ":libpolicy",
"../common-mk/external_dependencies:install_attributes-proto",
"../common-mk/external_dependencies:policy-protos",
"../common-mk/testrunner:testrunner",
@@ -558,9 +610,7 @@ if (use.test) {
if (use.fuzzer) {
executable("libbrillo_data_encoding_fuzzer") {
- sources = [
- "brillo/data_encoding_fuzzer.cc",
- ]
+ sources = [ "brillo/data_encoding_fuzzer.cc" ]
configs += [ "//common-mk/common_fuzzer:common_fuzzer" ]
@@ -568,15 +618,11 @@ if (use.fuzzer) {
include_dirs = [ "../libbrillo" ]
- deps = [
- ":libbrillo-core-${libbase_ver}",
- ]
+ deps = [ ":libbrillo-core" ]
}
executable("libbrillo_dbus_data_serialization_fuzzer") {
- sources = [
- "brillo/dbus/data_serialization_fuzzer.cc",
- ]
+ sources = [ "brillo/dbus/data_serialization_fuzzer.cc" ]
configs += [ "//common-mk/common_fuzzer:common_fuzzer" ]
@@ -584,15 +630,11 @@ if (use.fuzzer) {
include_dirs = [ "../libbrillo" ]
- deps = [
- ":libbrillo-core-${libbase_ver}",
- ]
+ deps = [ ":libbrillo-core" ]
}
executable("libbrillo_http_form_data_fuzzer") {
- sources = [
- "brillo/http/http_form_data_fuzzer.cc",
- ]
+ sources = [ "brillo/http/http_form_data_fuzzer.cc" ]
configs += [ "//common-mk/common_fuzzer:common_fuzzer" ]
@@ -601,19 +643,16 @@ if (use.fuzzer) {
include_dirs = [ "../libbrillo" ]
deps = [
- ":libbrillo-http-${libbase_ver}",
- ":libbrillo-streams-${libbase_ver}",
+ ":libbrillo-http",
+ ":libbrillo-streams",
]
}
}
copy("libinstallattributes-includes") {
- sources = [
- "install_attributes/libinstallattributes.h",
- ]
- outputs = [
- "${root_gen_dir}/include/install_attributes/{{source_file_part}}",
- ]
+ sources = [ "install_attributes/libinstallattributes.h" ]
+ outputs =
+ [ "${root_gen_dir}/include/install_attributes/{{source_file_part}}" ]
}
copy("libpolicy-includes") {
@@ -626,7 +665,5 @@ copy("libpolicy-includes") {
"policy/policy_util.h",
"policy/resilient_policy_util.h",
]
- outputs = [
- "${root_gen_dir}/include/policy/{{source_file_part}}",
- ]
+ outputs = [ "${root_gen_dir}/include/policy/{{source_file_part}}" ]
}
diff --git a/OWNERS b/OWNERS
index 6cee318..bd5625e 100644
--- a/OWNERS
+++ b/OWNERS
@@ -1,13 +1,9 @@
set noparent
# Android owners
-avakulenko@google.com
-dpursell@google.com
senj@google.com
-stevefung@google.com
# Chromium owners
-benchan@google.com
-derat@google.com
vapier@google.com
ejcaruso@google.com
+hidehiko@google.com
diff --git a/brillo/asynchronous_signal_handler.cc b/brillo/asynchronous_signal_handler.cc
index b8ec529..38b1787 100644
--- a/brillo/asynchronous_signal_handler.cc
+++ b/brillo/asynchronous_signal_handler.cc
@@ -11,49 +11,41 @@
#include <base/bind.h>
#include <base/files/file_util.h>
#include <base/logging.h>
-#include <base/message_loop/message_loop.h>
-#include <base/posix/eintr_wrapper.h>
-
-namespace {
-const int kInvalidDescriptor = -1;
-} // namespace
namespace brillo {
-AsynchronousSignalHandler::AsynchronousSignalHandler()
- : descriptor_(kInvalidDescriptor) {
+AsynchronousSignalHandler::AsynchronousSignalHandler() {
CHECK_EQ(sigemptyset(&signal_mask_), 0) << "Failed to initialize signal mask";
CHECK_EQ(sigemptyset(&saved_signal_mask_), 0)
<< "Failed to initialize signal mask";
}
AsynchronousSignalHandler::~AsynchronousSignalHandler() {
- if (descriptor_ != kInvalidDescriptor) {
- MessageLoop::current()->CancelTask(fd_watcher_task_);
+ fd_watcher_ = nullptr;
- if (IGNORE_EINTR(close(descriptor_)) != 0)
- PLOG(WARNING) << "Failed to close file descriptor";
+ if (!descriptor_.is_valid())
+ return;
- descriptor_ = kInvalidDescriptor;
- CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr));
- }
+ // Close FD before restoring sigprocmask.
+ descriptor_.reset();
+ CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr));
}
void AsynchronousSignalHandler::Init() {
- CHECK_EQ(kInvalidDescriptor, descriptor_);
+ // Making sure it is not yet initialized.
+ CHECK(!descriptor_.is_valid());
+
+ // Set sigprocmask before creating signalfd.
CHECK_EQ(0, sigprocmask(SIG_BLOCK, &signal_mask_, &saved_signal_mask_));
- descriptor_ =
- signalfd(descriptor_, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK);
- CHECK_NE(kInvalidDescriptor, descriptor_);
- fd_watcher_task_ = MessageLoop::current()->WatchFileDescriptor(
- FROM_HERE,
- descriptor_,
- MessageLoop::WatchMode::kWatchRead,
- true,
- base::Bind(&AsynchronousSignalHandler::OnFileCanReadWithoutBlocking,
- base::Unretained(this)));
- CHECK(fd_watcher_task_ != MessageLoop::kTaskIdNull)
- << "Watching shutdown pipe failed.";
+
+ // Creating signalfd, and start watching it.
+ descriptor_.reset(signalfd(-1, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK));
+ CHECK(descriptor_.is_valid());
+ fd_watcher_ = base::FileDescriptorWatcher::WatchReadable(
+ descriptor_.get(),
+ base::BindRepeating(&AsynchronousSignalHandler::OnReadable,
+ base::Unretained(this)));
+ CHECK(fd_watcher_) << "Watching signalfd failed.";
}
void AsynchronousSignalHandler::RegisterHandler(int signal,
@@ -65,15 +57,16 @@ void AsynchronousSignalHandler::RegisterHandler(int signal,
void AsynchronousSignalHandler::UnregisterHandler(int signal) {
Callbacks::iterator callback_it = registered_callbacks_.find(signal);
- if (callback_it != registered_callbacks_.end()) {
- registered_callbacks_.erase(callback_it);
- ResetSignal(signal);
- }
+ if (callback_it == registered_callbacks_.end())
+ return;
+ registered_callbacks_.erase(callback_it);
+ CHECK_EQ(0, sigdelset(&signal_mask_, signal));
+ UpdateSignals();
}
-void AsynchronousSignalHandler::OnFileCanReadWithoutBlocking() {
+void AsynchronousSignalHandler::OnReadable() {
struct signalfd_siginfo info;
- while (base::ReadFromFD(descriptor_,
+ while (base::ReadFromFD(descriptor_.get(),
reinterpret_cast<char*>(&info), sizeof(info))) {
int signal = info.ssi_signo;
Callbacks::iterator callback_it = registered_callbacks_.find(signal);
@@ -85,24 +78,29 @@ void AsynchronousSignalHandler::OnFileCanReadWithoutBlocking() {
}
const SignalHandler& callback = callback_it->second;
bool must_unregister = callback.Run(info);
- if (must_unregister) {
+ if (must_unregister)
UnregisterHandler(signal);
- }
}
}
-void AsynchronousSignalHandler::ResetSignal(int signal) {
- CHECK_EQ(0, sigdelset(&signal_mask_, signal));
- UpdateSignals();
-}
-
void AsynchronousSignalHandler::UpdateSignals() {
- if (descriptor_ != kInvalidDescriptor) {
- CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr));
- CHECK_EQ(0, sigprocmask(SIG_BLOCK, &signal_mask_, nullptr));
- CHECK_EQ(descriptor_,
- signalfd(descriptor_, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK));
+ if (!descriptor_.is_valid())
+ return;
+ sigset_t mask;
+#ifdef __ANDROID__
+ CHECK_EQ(0, sigemptyset(&mask));
+ for (size_t i = 0; i < NSIG; ++i) {
+ if (sigismember(&signal_mask_, i) == 1 || sigismember(&saved_signal_mask_, i) == 1) {
+ CHECK_EQ(0, sigaddset(&mask, i));
+ }
}
+#else
+ CHECK_EQ(0, sigorset(&mask, &signal_mask_, &saved_signal_mask_));
+#endif
+ CHECK_EQ(0, sigprocmask(SIG_SETMASK, &mask, nullptr));
+ CHECK_EQ(
+ descriptor_.get(),
+ signalfd(descriptor_.get(), &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK));
}
} // namespace brillo
diff --git a/brillo/asynchronous_signal_handler.h b/brillo/asynchronous_signal_handler.h
index ceae1ff..4b0edce 100644
--- a/brillo/asynchronous_signal_handler.h
+++ b/brillo/asynchronous_signal_handler.h
@@ -5,18 +5,16 @@
#ifndef LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_H_
#define LIBBRILLO_BRILLO_ASYNCHRONOUS_SIGNAL_HANDLER_H_
-#include <signal.h>
#include <sys/signalfd.h>
#include <map>
+#include <memory>
#include <base/callback.h>
-#include <base/compiler_specific.h>
-#include <base/macros.h>
-#include <base/message_loop/message_loop.h>
+#include <base/files/file_descriptor_watcher_posix.h>
+#include <base/files/scoped_file.h>
#include <brillo/asynchronous_signal_handler_interface.h>
#include <brillo/brillo_export.h>
-#include <brillo/message_loops/message_loop.h>
namespace brillo {
// Sets up signal handlers for registered signals, and converts signal receipt
@@ -25,10 +23,14 @@ namespace brillo {
class BRILLO_EXPORT AsynchronousSignalHandler final :
public AsynchronousSignalHandlerInterface {
public:
+ using AsynchronousSignalHandlerInterface::SignalHandler;
+
AsynchronousSignalHandler();
~AsynchronousSignalHandler() override;
- using AsynchronousSignalHandlerInterface::SignalHandler;
+ AsynchronousSignalHandler(const AsynchronousSignalHandler&) = delete;
+ AsynchronousSignalHandler&
+ operator=(const AsynchronousSignalHandler&) = delete;
// Initialize the handler.
void Init();
@@ -40,17 +42,20 @@ class BRILLO_EXPORT AsynchronousSignalHandler final :
private:
// Called from the main loop when we can read from |descriptor_|, indicated
// that a signal was processed.
- void OnFileCanReadWithoutBlocking();
+ void OnReadable();
- // Controller used to manage watching of signalling pipe.
- MessageLoop::TaskId fd_watcher_task_{MessageLoop::kTaskIdNull};
+ // Updates the set of signals that this handler listens to.
+ BRILLO_PRIVATE void UpdateSignals();
- // The registered callbacks.
- typedef std::map<int, SignalHandler> Callbacks;
+ // Map from signal to its registered callback.
+ using Callbacks = std::map<int, SignalHandler>;
Callbacks registered_callbacks_;
// File descriptor for accepting signals indicated by |signal_mask_|.
- int descriptor_;
+ base::ScopedFD descriptor_;
+
+ // Controller used to manage watching of signalling pipe.
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> fd_watcher_;
// A set of signals to be handled after the dispatcher is running.
sigset_t signal_mask_;
@@ -58,15 +63,6 @@ class BRILLO_EXPORT AsynchronousSignalHandler final :
// A copy of the signal mask before the dispatcher starts, which will be
// used to restore to the original state when the dispatcher stops.
sigset_t saved_signal_mask_;
-
- // Resets the given signal to its default behavior. Doesn't touch
- // |registered_callbacks_|.
- BRILLO_PRIVATE void ResetSignal(int signal);
-
- // Updates the set of signals that this handler listens to.
- BRILLO_PRIVATE void UpdateSignals();
-
- DISALLOW_COPY_AND_ASSIGN(AsynchronousSignalHandler);
};
} // namespace brillo
diff --git a/brillo/asynchronous_signal_handler_interface.h b/brillo/asynchronous_signal_handler_interface.h
index ef0012d..7bae444 100644
--- a/brillo/asynchronous_signal_handler_interface.h
+++ b/brillo/asynchronous_signal_handler_interface.h
@@ -20,7 +20,8 @@ class BRILLO_EXPORT AsynchronousSignalHandlerInterface {
virtual ~AsynchronousSignalHandlerInterface() = default;
// The callback called when a signal is received.
- using SignalHandler = base::Callback<bool(const struct signalfd_siginfo&)>;
+ using SignalHandler =
+ base::RepeatingCallback<bool(const struct signalfd_siginfo&)>;
// Register a new handler for the given |signal|, replacing any previously
// registered handler. |callback| will be called on the thread the
diff --git a/brillo/binder_watcher.cc b/brillo/binder_watcher.cc
index 9752204..51b0f59 100644
--- a/brillo/binder_watcher.cc
+++ b/brillo/binder_watcher.cc
@@ -33,24 +33,11 @@ void OnBinderReadReady() {
namespace brillo {
-BinderWatcher::BinderWatcher(MessageLoop* message_loop)
- : message_loop_(message_loop) {}
+BinderWatcher::BinderWatcher() = default;
-BinderWatcher::BinderWatcher() : message_loop_(nullptr) {}
-
-BinderWatcher::~BinderWatcher() {
- if (task_id_ != MessageLoop::kTaskIdNull)
- message_loop_->CancelTask(task_id_);
-}
+BinderWatcher::~BinderWatcher() = default;
bool BinderWatcher::Init() {
- if (!message_loop_)
- message_loop_ = MessageLoop::current();
- if (!message_loop_) {
- LOG(ERROR) << "Must initialize a brillo::MessageLoop to use BinderWatcher";
- return false;
- }
-
int binder_fd = -1;
ProcessState::self()->setThreadPoolMaxThreadCount(0);
IPCThreadState::self()->disableBackgroundScheduling(true);
@@ -66,13 +53,10 @@ bool BinderWatcher::Init() {
}
VLOG(1) << "Got binder FD " << binder_fd;
- task_id_ = message_loop_->WatchFileDescriptor(
- FROM_HERE,
+ watcher_ = base::FileDescriptorWatcher::WatchReadable(
binder_fd,
- MessageLoop::kWatchRead,
- true /* persistent */,
- base::Bind(&OnBinderReadReady));
- if (task_id_ == MessageLoop::kTaskIdNull) {
+ base::BindRepeating(&OnBinderReadReady));
+ if (!watcher_) {
LOG(ERROR) << "Failed to watch binder FD";
return false;
}
diff --git a/brillo/binder_watcher.h b/brillo/binder_watcher.h
index ece999d..d7af50e 100644
--- a/brillo/binder_watcher.h
+++ b/brillo/binder_watcher.h
@@ -17,8 +17,10 @@
#ifndef LIBBRILLO_BRILLO_BINDER_WATCHER_H_
#define LIBBRILLO_BRILLO_BINDER_WATCHER_H_
+#include <memory>
+
+#include <base/files/file_descriptor_watcher_posix.h>
#include <base/macros.h>
-#include <brillo/message_loops/message_loop.h>
namespace brillo {
@@ -26,9 +28,6 @@ namespace brillo {
// make the message loop watch for binder events and pass them to libbinder.
class BinderWatcher final {
public:
- // Construct the BinderWatcher using the passed |message_loop| if not null or
- // the current MessageLoop otherwise.
- explicit BinderWatcher(MessageLoop* message_loop);
BinderWatcher();
~BinderWatcher();
@@ -36,8 +35,7 @@ class BinderWatcher final {
bool Init();
private:
- MessageLoop::TaskId task_id_{MessageLoop::kTaskIdNull};
- MessageLoop* message_loop_;
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> watcher_;
DISALLOW_COPY_AND_ASSIGN(BinderWatcher);
};
diff --git a/brillo/blkdev_utils/loop_device.cc b/brillo/blkdev_utils/loop_device.cc
index bd1b67c..2b2219d 100644
--- a/brillo/blkdev_utils/loop_device.cc
+++ b/brillo/blkdev_utils/loop_device.cc
@@ -72,7 +72,8 @@ int GetDeviceNumber(const base::FilePath& sys_block_loopdev_path) {
std::vector<std::string> device_ids = base::SplitString(
device_string, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
- if (device_ids.size() != 2 || device_ids[0] != base::IntToString(LOOP_MAJOR))
+ if (device_ids.size() != 2 ||
+ device_ids[0] != base::NumberToString(LOOP_MAJOR))
return -1;
base::StringToInt(device_ids[1], &device_number);
diff --git a/brillo/cryptohome.cc b/brillo/cryptohome.cc
index 88e4739..a82356e 100644
--- a/brillo/cryptohome.cc
+++ b/brillo/cryptohome.cc
@@ -41,7 +41,7 @@ static char g_system_salt_path[PATH_MAX] = "/home/.shadow/salt";
static std::string* salt = nullptr;
-static bool EnsureSystemSaltIsLoaded() {
+bool EnsureSystemSaltIsLoaded() {
if (salt && !salt->empty())
return true;
FilePath salt_path(g_system_salt_path);
diff --git a/brillo/cryptohome.h b/brillo/cryptohome.h
index 798d3a0..a9d5927 100644
--- a/brillo/cryptohome.h
+++ b/brillo/cryptohome.h
@@ -74,6 +74,9 @@ BRILLO_EXPORT void SetSystemSalt(std::string* salt);
// Returns the system salt.
BRILLO_EXPORT std::string* GetSystemSalt();
+// Ensures the system salt is loaded in the memory.
+BRILLO_EXPORT bool EnsureSystemSaltIsLoaded();
+
} // namespace home
} // namespace cryptohome
} // namespace brillo
diff --git a/brillo/daemons/daemon.cc b/brillo/daemons/daemon.cc
index b706017..82de826 100644
--- a/brillo/daemons/daemon.cc
+++ b/brillo/daemons/daemon.cc
@@ -4,6 +4,7 @@
#include <brillo/daemons/daemon.h>
+#include <signal.h>
#include <sysexits.h>
#include <time.h>
@@ -27,7 +28,7 @@ int Daemon::Run() {
return exit_code;
message_loop_.PostTask(
- base::Bind(&Daemon::OnEventLoopStartedTask, base::Unretained(this)));
+ base::BindOnce(&Daemon::OnEventLoopStartedTask, base::Unretained(this)));
message_loop_.Run();
OnShutdown(&exit_code_);
diff --git a/brillo/dbus/data_serialization.cc b/brillo/dbus/data_serialization.cc
index fa348a0..5f47d67 100644
--- a/brillo/dbus/data_serialization.cc
+++ b/brillo/dbus/data_serialization.cc
@@ -320,7 +320,6 @@ bool PopValueFromReader(dbus::MessageReader* reader, brillo::Any* value) {
LOG(FATAL) << "Unknown D-Bus data type: " << variant_reader.GetDataType();
return false;
}
- return true;
}
} // namespace dbus_utils
diff --git a/brillo/dbus/dbus_method_invoker_test.cc b/brillo/dbus/dbus_method_invoker_test.cc
index 9e6600a..c0c681b 100644
--- a/brillo/dbus/dbus_method_invoker_test.cc
+++ b/brillo/dbus/dbus_method_invoker_test.cc
@@ -83,18 +83,16 @@ class DBusMethodInvokerTest : public testing::Test {
GetObjectProxy(kTestServiceName, dbus::ObjectPath(kTestPath)))
.WillRepeatedly(Return(mock_object_proxy_.get()));
int def_timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
- EXPECT_CALL(
- *mock_object_proxy_,
- MIGRATE_MockCallMethodAndBlockWithErrorDetails(_, def_timeout_ms, _))
+ EXPECT_CALL(*mock_object_proxy_,
+ CallMethodAndBlockWithErrorDetails(_, def_timeout_ms, _))
.WillRepeatedly(Invoke(this, &DBusMethodInvokerTest::CreateResponse));
}
void TearDown() override { bus_ = nullptr; }
- MIGRATE_WrapObjectProxyResponseType(Response)
- CreateResponse(dbus::MethodCall* method_call,
- int /* timeout_ms */,
- dbus::ScopedDBusError* dbus_error) {
+ std::unique_ptr<Response> CreateResponse(dbus::MethodCall* method_call,
+ int /* timeout_ms */,
+ dbus::ScopedDBusError* dbus_error) {
if (method_call->GetInterface() == kTestInterface) {
if (method_call->GetMember() == kTestMethod1) {
MessageReader reader(method_call);
@@ -105,12 +103,12 @@ class DBusMethodInvokerTest : public testing::Test {
auto response = Response::CreateEmpty();
MessageWriter writer(response.get());
writer.AppendString(std::to_string(v1 + v2));
- return MIGRATE_WrapObjectProxyResponseConversion(response);
+ return response;
}
} else if (method_call->GetMember() == kTestMethod2) {
method_call->SetSerial(123);
dbus_set_error(dbus_error->get(), "org.MyError", "My error message");
- return MIGRATE_WrapObjectProxyResponseEmpty;
+ return std::unique_ptr<dbus::Response>();
} else if (method_call->GetMember() == kTestMethod3) {
MessageReader reader(method_call);
dbus_utils_test::TestMessage msg;
@@ -118,7 +116,7 @@ class DBusMethodInvokerTest : public testing::Test {
auto response = Response::CreateEmpty();
MessageWriter writer(response.get());
AppendValueToWriter(&writer, msg);
- return MIGRATE_WrapObjectProxyResponseConversion(response);
+ return response;
}
} else if (method_call->GetMember() == kTestMethod4) {
method_call->SetSerial(123);
@@ -128,13 +126,13 @@ class DBusMethodInvokerTest : public testing::Test {
auto response = Response::CreateEmpty();
MessageWriter writer(response.get());
writer.AppendFileDescriptor(fd.get());
- return MIGRATE_WrapObjectProxyResponseConversion(response);
+ return response;
}
}
}
LOG(ERROR) << "Unexpected method call: " << method_call->ToString();
- return MIGRATE_WrapObjectProxyResponseEmpty;
+ return std::unique_ptr<dbus::Response>();
}
std::string CallTestMethod(int v1, int v2) {
@@ -245,7 +243,7 @@ class AsyncDBusMethodInvokerTest : public testing::Test {
.WillRepeatedly(Return(mock_object_proxy_.get()));
int def_timeout_ms = dbus::ObjectProxy::TIMEOUT_USE_DEFAULT;
EXPECT_CALL(*mock_object_proxy_,
- MIGRATE_CallMethodWithErrorCallback(_, def_timeout_ms, _, _))
+ DoCallMethodWithErrorCallback(_, def_timeout_ms, _, _))
.WillRepeatedly(Invoke(this, &AsyncDBusMethodInvokerTest::HandleCall));
}
@@ -253,10 +251,8 @@ class AsyncDBusMethodInvokerTest : public testing::Test {
void HandleCall(dbus::MethodCall* method_call,
int /* timeout_ms */,
- dbus::ObjectProxy::ResponseCallback
- MIGRATE_WrapObjectProxyCallback(success_callback),
- dbus::ObjectProxy::ErrorCallback
- MIGRATE_WrapObjectProxyCallback(error_callback)) {
+ dbus::ObjectProxy::ResponseCallback* success_callback,
+ dbus::ObjectProxy::ErrorCallback* error_callback) {
if (method_call->GetInterface() == kTestInterface) {
if (method_call->GetMember() == kTestMethod1) {
MessageReader reader(method_call);
@@ -267,16 +263,14 @@ class AsyncDBusMethodInvokerTest : public testing::Test {
auto response = Response::CreateEmpty();
MessageWriter writer(response.get());
writer.AppendString(std::to_string(v1 + v2));
- std::move(MIGRATE_WrapObjectProxyCallback(success_callback))
- .Run(response.get());
+ std::move(*success_callback).Run(response.get());
}
return;
} else if (method_call->GetMember() == kTestMethod2) {
method_call->SetSerial(123);
auto error_response = dbus::ErrorResponse::FromMethodCall(
method_call, "org.MyError", "My error message");
- std::move(MIGRATE_WrapObjectProxyCallback(error_callback))
- .Run(error_response.get());
+ std::move(*error_callback).Run(error_response.get());
return;
}
}
diff --git a/brillo/dbus/dbus_object.cc b/brillo/dbus/dbus_object.cc
index 12eb353..502af3e 100644
--- a/brillo/dbus/dbus_object.cc
+++ b/brillo/dbus/dbus_object.cc
@@ -9,6 +9,7 @@
#include <vector>
#include <base/bind.h>
+#include <base/bind_helpers.h>
#include <base/logging.h>
#include <brillo/dbus/async_event_sequencer.h>
#include <brillo/dbus/exported_object_manager.h>
@@ -41,8 +42,7 @@ DBusInterface::DBusInterface(DBusObject* dbus_object,
const std::string& interface_name)
: dbus_object_(dbus_object),
interface_name_(interface_name),
- // TODO(crbug.com/909719): Use base::DoNothing()
- release_interface_cb_(base::Bind([]() {})) {}
+ release_interface_cb_(base::DoNothing()) {}
void DBusInterface::AddProperty(const std::string& property_name,
ExportedPropertyBase* prop_base) {
diff --git a/brillo/dbus/dbus_property.h b/brillo/dbus/dbus_property.h
index 77b7328..f82759e 100644
--- a/brillo/dbus/dbus_property.h
+++ b/brillo/dbus/dbus_property.h
@@ -5,6 +5,8 @@
#ifndef LIBBRILLO_BRILLO_DBUS_DBUS_PROPERTY_H_
#define LIBBRILLO_BRILLO_DBUS_DBUS_PROPERTY_H_
+#include <utility>
+
#include <brillo/dbus/data_serialization.h>
#include <dbus/property.h>
@@ -42,7 +44,7 @@ class Property : public ::dbus::PropertyBase {
// remote object.
void Set(const T& value, ::dbus::PropertySet::SetCallback callback) {
set_value_ = value;
- property_set()->Set(this, callback);
+ property_set()->Set(this, std::move(callback));
}
// Synchronous version of Set().
diff --git a/brillo/dbus/dbus_signal_handler_test.cc b/brillo/dbus/dbus_signal_handler_test.cc
index edd0eca..35bad65 100644
--- a/brillo/dbus/dbus_signal_handler_test.cc
+++ b/brillo/dbus/dbus_signal_handler_test.cc
@@ -50,7 +50,7 @@ class DBusSignalHandlerTest : public testing::Test {
void CallSignal(SignalHandlerSink* sink, Args... args) {
dbus::ObjectProxy::SignalCallback signal_callback;
EXPECT_CALL(*mock_object_proxy_,
- MIGRATE_ConnectToSignal(kInterface, kSignal, _, _))
+ DoConnectToSignal(kInterface, kSignal, _, _))
.WillOnce(SaveArg<2>(&signal_callback));
brillo::dbus_utils::ConnectToSignal(
@@ -71,8 +71,7 @@ class DBusSignalHandlerTest : public testing::Test {
};
TEST_F(DBusSignalHandlerTest, ConnectToSignal) {
- EXPECT_CALL(*mock_object_proxy_,
- MIGRATE_ConnectToSignal(kInterface, kSignal, _, _))
+ EXPECT_CALL(*mock_object_proxy_, DoConnectToSignal(kInterface, kSignal, _, _))
.Times(1);
brillo::dbus_utils::ConnectToSignal(
diff --git a/brillo/dbus/exported_object_manager.cc b/brillo/dbus/exported_object_manager.cc
index 61dae68..a2ae1fe 100644
--- a/brillo/dbus/exported_object_manager.cc
+++ b/brillo/dbus/exported_object_manager.cc
@@ -89,11 +89,11 @@ ExportedObjectManager::HandleGetManagedObjects() {
// DICT<STRING,VARIANT>>> )
bus_->AssertOnOriginThread();
ExportedObjectManager::ObjectMap objects;
- for (const auto path_pair : registered_objects_) {
+ for (const auto& path_pair : registered_objects_) {
std::map<std::string, VariantDictionary>& interfaces =
objects[path_pair.first];
const InterfaceProperties& interface2properties = path_pair.second;
- for (const auto interface : interface2properties) {
+ for (const auto& interface : interface2properties) {
interface.second.Run(&interfaces[interface.first]);
}
}
diff --git a/brillo/file_utils.cc b/brillo/file_utils.cc
index b4370d1..3661551 100644
--- a/brillo/file_utils.cc
+++ b/brillo/file_utils.cc
@@ -11,11 +11,13 @@
#include <utility>
#include <vector>
+#include <base/files/file_enumerator.h>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/posix/eintr_wrapper.h>
#include <base/rand_util.h>
+#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringprintf.h>
#include <base/time/time.h>
@@ -140,7 +142,7 @@ bool TouchFileInternal(const base::FilePath& path,
std::string GetRandomSuffix() {
const int kBufferSize = 6;
unsigned char buffer[kBufferSize];
- base::RandBytes(buffer, arraysize(buffer));
+ base::RandBytes(buffer, base::size(buffer));
std::string suffix;
for (int i = 0; i < kBufferSize; ++i) {
int random_value = buffer[i] % (2 * 26 + 10);
@@ -505,4 +507,20 @@ bool WriteToFileAtomic(const base::FilePath& path,
return true;
}
+int64_t ComputeDirectoryDiskUsage(const base::FilePath& root_path) {
+ constexpr size_t S_BLKSIZE = 512;
+ int64_t running_blocks = 0;
+ base::FileEnumerator file_iter(root_path, true,
+ base::FileEnumerator::FILES |
+ base::FileEnumerator::DIRECTORIES |
+ base::FileEnumerator::SHOW_SYM_LINKS);
+ while (!file_iter.Next().empty()) {
+ // st_blocks in struct stat is the number of S_BLKSIZE (512) bytes sized
+ // blocks occupied by this file.
+ running_blocks += file_iter.GetInfo().stat().st_blocks;
+ }
+ // Each block is S_BLKSIZE (512) bytes so *S_BLKSIZE.
+ return running_blocks * S_BLKSIZE;
+}
+
} // namespace brillo
diff --git a/brillo/file_utils.h b/brillo/file_utils.h
index 3862a43..f328165 100644
--- a/brillo/file_utils.h
+++ b/brillo/file_utils.h
@@ -144,6 +144,48 @@ BRILLO_EXPORT bool WriteBlobToFileAtomic(const base::FilePath& path,
blob.size(), mode);
}
+// ComputeDirectoryDiskUsage() is similar to base::ComputeDirectorySize() in
+// libbase, but it returns the actual disk usage instead of the apparent size.
+// In another word, ComputeDirectoryDiskUsage() behaves like "du -s
+// --apparent-size", and ComputeDirectorySize() behaves like "du -s". The
+// primary difference is that sparse file and files on filesystem with
+// transparent compression will report smaller file size than
+// ComputeDirectorySize(). Returns the total used bytes.
+// The following behaviours of this function is guaranteed and is verified by
+// unit tests:
+// - This function recursively processes directory down the tree, so disk space
+// used by files in all the subdirectories are counted.
+// - Symbolic links will not be followed (the size of link itself is counted,
+// the target is not)
+// - Hidden files are counted as well.
+// The following behaviours are not guaranteed, and it is recommended to avoid
+// them in the field. Their current behaviour is provided for reference only:
+// - This function doesn't care about filesystem boundaries, so it'll cross
+// filesystem boundary to count file size if there's one in the specified
+// directory.
+// - Hard links will be treated like normal files, so they could be
+// over-reported.
+// - Directories that the current user doesn't have permission to list/stat will
+// be ignored, and an error will be logged but the returned result could be
+// under-reported without error in the returned value.
+// - Deduplication (should the filesystem support it) is ignored, and the result
+// could be over-reported.
+// - Doesn't check if |root_path| exists, a non-existent directory will results
+// in 0 bytes without any error.
+// - There are no limit on the depth of file system tree, the program will crash
+// if it run out of memory to hold the entire depth of file system tree.
+// - If the directory is modified during this function call, there's no
+// guarantee on if the function will count the updated or original file system
+// state. The function could choose to count the updated state for one file and
+// original state for another file.
+// - Non-POSIX system is not supported.
+// - Disk space used by directory (and its subdirectories) itself is counted.
+//
+// Parameters
+// root_path - The directory to compute the size for
+BRILLO_EXPORT int64_t
+ComputeDirectoryDiskUsage(const base::FilePath& root_path);
+
} // namespace brillo
#endif // LIBBRILLO_BRILLO_FILE_UTILS_H_
diff --git a/brillo/file_utils_test.cc b/brillo/file_utils_test.cc
index 9a1f646..3407cd1 100644
--- a/brillo/file_utils_test.cc
+++ b/brillo/file_utils_test.cc
@@ -13,6 +13,7 @@
#include <base/files/file_util.h>
#include <base/files/scoped_temp_dir.h>
#include <base/rand_util.h>
+#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <gtest/gtest.h>
@@ -29,8 +30,8 @@ constexpr int kPermissions755 = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
std::string GetRandomSuffix() {
const int kBufferSize = 6;
unsigned char buffer[kBufferSize];
- base::RandBytes(buffer, arraysize(buffer));
- return base::HexEncode(buffer, arraysize(buffer));
+ base::RandBytes(buffer, base::size(buffer));
+ return base::HexEncode(buffer, base::size(buffer));
}
bool IsNonBlockingFD(int fd) {
@@ -343,4 +344,165 @@ TEST_F(FileUtilsTest,
umask(old_mask);
}
+TEST_F(FileUtilsTest, ComputeDirectoryDiskUsageNormalRandomFile) {
+ // 2MB test file.
+ constexpr size_t kFileSize = 2 * 1024 * 1024;
+
+ const base::FilePath dirname(GetTempName());
+ EXPECT_TRUE(base::CreateDirectory(dirname));
+ const base::FilePath filename = dirname.Append("test.temp");
+
+ std::string file_content = base::RandBytesAsString(kFileSize);
+ EXPECT_TRUE(WriteStringToFile(filename, file_content));
+
+ int64_t result_usage = ComputeDirectoryDiskUsage(dirname);
+ int64_t result_size = base::ComputeDirectorySize(dirname);
+
+ // result_usage (what we are testing here) should be within +/-10% of ground
+ // truth. The variation is to account for filesystem overhead variations.
+ EXPECT_GT(result_usage, kFileSize / 10 * 9);
+ EXPECT_LT(result_usage, kFileSize / 10 * 11);
+
+ // result_usage should be close to result_size, because the test file is
+ // random so it's disk usage should be similar to apparent size.
+ EXPECT_GT(result_usage, result_size / 10 * 9);
+ EXPECT_LT(result_usage, result_size / 10 * 11);
+}
+
+TEST_F(FileUtilsTest, ComputeDirectoryDiskUsageDeepRandomFile) {
+ // 2MB test file.
+ constexpr size_t kFileSize = 2 * 1024 * 1024;
+
+ const base::FilePath dirname(GetTempName());
+ EXPECT_TRUE(base::CreateDirectory(dirname));
+ base::FilePath currentlevel = dirname;
+ for (int i = 0; i < 10; i++) {
+ base::FilePath nextlevel = currentlevel.Append("test.dir");
+ EXPECT_TRUE(base::CreateDirectory(nextlevel));
+ currentlevel = nextlevel;
+ }
+ const base::FilePath filename = currentlevel.Append("test.temp");
+
+ std::string file_content = base::RandBytesAsString(kFileSize);
+ EXPECT_TRUE(WriteStringToFile(filename, file_content));
+
+ int64_t result_usage = ComputeDirectoryDiskUsage(dirname);
+ int64_t result_size = base::ComputeDirectorySize(dirname);
+
+ // result_usage (what we are testing here) should be within +/-10% of ground
+ // truth. The variation is to account for filesystem overhead variations.
+ EXPECT_GT(result_usage, kFileSize / 10 * 9);
+ EXPECT_LT(result_usage, kFileSize / 10 * 11);
+
+ // result_usage should be close to result_size, because the test file is
+ // random so it's disk usage should be similar to apparent size.
+ EXPECT_GT(result_usage, result_size / 10 * 9);
+ EXPECT_LT(result_usage, result_size / 10 * 11);
+}
+
+TEST_F(FileUtilsTest, ComputeDirectoryDiskUsageHiddenRandomFile) {
+ // 2MB test file.
+ constexpr size_t kFileSize = 2 * 1024 * 1024;
+
+ const base::FilePath dirname(GetTempName());
+ EXPECT_TRUE(base::CreateDirectory(dirname));
+ // File name starts with a dot, so it's a hidden file.
+ const base::FilePath filename = dirname.Append(".test.temp");
+
+ std::string file_content = base::RandBytesAsString(kFileSize);
+ EXPECT_TRUE(WriteStringToFile(filename, file_content));
+
+ int64_t result_usage = ComputeDirectoryDiskUsage(dirname);
+ int64_t result_size = base::ComputeDirectorySize(dirname);
+
+ // result_usage (what we are testing here) should be within +/-10% of ground
+ // truth. The variation is to account for filesystem overhead variations.
+ EXPECT_GT(result_usage, kFileSize / 10 * 9);
+ EXPECT_LT(result_usage, kFileSize / 10 * 11);
+
+ // result_usage should be close to result_size, because the test file is
+ // random so it's disk usage should be similar to apparent size.
+ EXPECT_GT(result_usage, result_size / 10 * 9);
+ EXPECT_LT(result_usage, result_size / 10 * 11);
+}
+
+TEST_F(FileUtilsTest, ComputeDirectoryDiskUsageSparseFile) {
+ // 128MB sparse test file.
+ constexpr size_t kFileSize = 128 * 1024 * 1024;
+ constexpr size_t kFileSizeThreshold = 64 * 1024;
+
+ const base::FilePath dirname(GetTempName());
+ EXPECT_TRUE(base::CreateDirectory(dirname));
+ const base::FilePath filename = dirname.Append("test.temp");
+
+ int fd =
+ open(filename.value().c_str(), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
+ EXPECT_NE(fd, -1);
+ // Calling ftruncate on an empty file will create a sparse file.
+ EXPECT_EQ(0, ftruncate(fd, kFileSize));
+
+ int64_t result_usage = ComputeDirectoryDiskUsage(dirname);
+ int64_t result_size = base::ComputeDirectorySize(dirname);
+
+ // result_usage (what we are testing here) should be less than
+ // kFileSizeThreshold, the threshold is to account for filesystem overhead
+ // variations.
+ EXPECT_LT(result_usage, kFileSizeThreshold);
+
+ // Since we are dealing with sparse files here, the apparent size should be
+ // much much larger than the actual disk usage.
+ EXPECT_LT(result_usage, result_size / 1000);
+}
+
+TEST_F(FileUtilsTest, ComputeDirectoryDiskUsageSymlinkFile) {
+ // 2MB test file.
+ constexpr size_t kFileSize = 2 * 1024 * 1024;
+
+ const base::FilePath dirname(GetTempName());
+ EXPECT_TRUE(base::CreateDirectory(dirname));
+ const base::FilePath filename = dirname.Append("test.temp");
+ const base::FilePath linkname = dirname.Append("test.link");
+
+ std::string file_content = base::RandBytesAsString(kFileSize);
+ EXPECT_TRUE(WriteStringToFile(filename, file_content));
+
+ // Create a symlink.
+ EXPECT_TRUE(base::CreateSymbolicLink(filename, linkname));
+
+ int64_t result_usage = ComputeDirectoryDiskUsage(dirname);
+
+ // result_usage (what we are testing here) should be within +/-10% of ground
+ // truth. The variation is to account for filesystem overhead variations.
+ // Note that it's not 2x kFileSize because symblink is not counted twice.
+ EXPECT_GT(result_usage, kFileSize / 10 * 9);
+ EXPECT_LT(result_usage, kFileSize / 10 * 11);
+}
+
+TEST_F(FileUtilsTest, ComputeDirectoryDiskUsageSymlinkDir) {
+ // 2MB test file.
+ constexpr size_t kFileSize = 2 * 1024 * 1024;
+
+ const base::FilePath parentname(GetTempName());
+ EXPECT_TRUE(base::CreateDirectory(parentname));
+ const base::FilePath dirname = parentname.Append("target.dir");
+ EXPECT_TRUE(base::CreateDirectory(dirname));
+ const base::FilePath linkname = parentname.Append("link.dir");
+
+ const base::FilePath filename = dirname.Append("test.temp");
+
+ std::string file_content = base::RandBytesAsString(kFileSize);
+ EXPECT_TRUE(WriteStringToFile(filename, file_content));
+
+ // Create a symlink.
+ EXPECT_TRUE(base::CreateSymbolicLink(dirname, linkname));
+
+ int64_t result_usage = ComputeDirectoryDiskUsage(dirname);
+
+ // result_usage (what we are testing here) should be within +/-10% of ground
+ // truth. The variation is to account for filesystem overhead variations.
+ // Note that it's not 2x kFileSize because symblink is not counted twice.
+ EXPECT_GT(result_usage, kFileSize / 10 * 9);
+ EXPECT_LT(result_usage, kFileSize / 10 * 11);
+}
+
} // namespace brillo
diff --git a/brillo/files/file_util_test.cc b/brillo/files/file_util_test.cc
index 98d28fc..f1ba527 100644
--- a/brillo/files/file_util_test.cc
+++ b/brillo/files/file_util_test.cc
@@ -6,6 +6,7 @@
#include <base/files/file_util.h>
#include <base/rand_util.h>
+#include <base/stl_util.h>
#include <base/strings/string_number_conversions.h>
#include <brillo/files/file_util.h>
#include <brillo/files/safe_fd.h>
@@ -42,8 +43,8 @@ std::ostream& operator<<(std::ostream& os, const brillo::SafeFD::Error err) {
std::string GetRandomSuffix() {
const int kBufferSize = 6;
unsigned char buffer[kBufferSize];
- base::RandBytes(buffer, arraysize(buffer));
- return base::HexEncode(buffer, arraysize(buffer));
+ base::RandBytes(buffer, base::size(buffer));
+ return base::HexEncode(buffer, base::size(buffer));
}
void FileTest::SetUpTestCase() {
diff --git a/brillo/files/safe_fd.cc b/brillo/files/safe_fd.cc
index 855207d..ac19dc3 100644
--- a/brillo/files/safe_fd.cc
+++ b/brillo/files/safe_fd.cc
@@ -446,7 +446,8 @@ SafeFD::Error SafeFD::Unlink(const std::string& name) {
SafeFD::Error SafeFD::Rmdir(const std::string& name,
bool recursive,
- size_t max_depth) {
+ size_t max_depth,
+ bool keep_going) {
if (!fd_.is_valid()) {
return SafeFD::Error::kNotInitialized;
}
@@ -460,6 +461,8 @@ SafeFD::Error SafeFD::Rmdir(const std::string& name,
return err;
}
+ SafeFD::Error last_err = SafeFD::Error::kNoError;
+
if (recursive) {
SafeFD dir_fd;
std::tie(dir_fd, err) =
@@ -490,32 +493,36 @@ SafeFD::Error SafeFD::Rmdir(const std::string& name,
errno = 0;
const dirent* entry = HANDLE_EINTR_IF_EQ(readdir(dir.get()), nullptr);
while (entry != nullptr) {
- if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
- goto continue_;
- }
+ SafeFD::Error err = [&]() {
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0) {
+ return SafeFD::Error::kNoError;
+ }
- struct stat child_info;
- if (fstatat(dir_fd.get(), entry->d_name, &child_info,
- AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW) != 0) {
- return SafeFD::Error::kIOError;
- }
+ struct stat child_info;
+ if (fstatat(dir_fd.get(), entry->d_name, &child_info,
+ AT_NO_AUTOMOUNT | AT_SYMLINK_NOFOLLOW) != 0) {
+ return SafeFD::Error::kIOError;
+ }
- if (child_info.st_dev != dir_info.st_dev) {
- return SafeFD::Error::kBoundaryDetected;
- }
+ if (child_info.st_dev != dir_info.st_dev) {
+ return SafeFD::Error::kBoundaryDetected;
+ }
- SafeFD::Error err;
- if (entry->d_type == DT_DIR) {
- err = dir_fd.Rmdir(entry->d_name, true, max_depth - 1);
- } else {
- err = dir_fd.Unlink(entry->d_name);
- }
+ if (entry->d_type != DT_DIR) {
+ return dir_fd.Unlink(entry->d_name);
+ }
+
+ return dir_fd.Rmdir(entry->d_name, true, max_depth - 1, keep_going);
+ }();
if (IsError(err)) {
- return err;
+ if (!keep_going) {
+ return err;
+ }
+ last_err = err;
}
- continue_:
errno = 0;
entry = HANDLE_EINTR_IF_EQ(readdir(dir.get()), nullptr);
}
@@ -530,9 +537,16 @@ SafeFD::Error SafeFD::Rmdir(const std::string& name,
if (errno == ENOTDIR) {
return SafeFD::Error::kWrongType;
}
+ // If there was an error during the recursive delete, we expect unlink
+ // to fail with ENOTEMPTY and we bubble the error from recursion
+ // instead.
+ if (IsError(last_err) && errno == ENOTEMPTY) {
+ return last_err;
+ }
return SafeFD::Error::kIOError;
}
- return SafeFD::Error::kNoError;
+
+ return last_err;
}
} // namespace brillo
diff --git a/brillo/files/safe_fd.h b/brillo/files/safe_fd.h
index 5e126b4..3c77362 100644
--- a/brillo/files/safe_fd.h
+++ b/brillo/files/safe_fd.h
@@ -183,10 +183,13 @@ class SafeFD {
// recursive - if true also unlink child paths.
// max_depth - limit on recursion depth to prevent fd exhaustion and stack
// overflows.
+ // keep_going - in recursive case continue deleting even in the face of
+ // errors. If all entries cannot be deleted, the last error encountered
+ // during recursion is returned.
BRILLO_EXPORT Error Rmdir(const std::string& name,
bool recursive = false,
- size_t max_depth = kDefaultMaxPathDepth)
- WARN_UNUSED_RESULT;
+ size_t max_depth = kDefaultMaxPathDepth,
+ bool keep_going = true) WARN_UNUSED_RESULT;
private:
BRILLO_EXPORT static const char* RootPath;
diff --git a/brillo/files/safe_fd_test.cc b/brillo/files/safe_fd_test.cc
index fff3a6c..6401f3d 100644
--- a/brillo/files/safe_fd_test.cc
+++ b/brillo/files/safe_fd_test.cc
@@ -624,4 +624,75 @@ TEST_F(SafeFDTest, Rmdir_WrongType) {
EXPECT_EQ(subdir.first.Rmdir(kFileName), SafeFD::Error::kWrongType);
}
+TEST_F(SafeFDTest, Rmdir_Recursive_KeepGoing) {
+ ASSERT_TRUE(SetupSubdir());
+
+ ASSERT_TRUE(base::CreateDirectory(sub_dir_path_.Append(kSubdirName)));
+
+ // Give us something to iterate over.
+ constexpr int kNumSentinel = 25;
+ for (int i = 0; i < kNumSentinel; i++) {
+ SafeFD::SafeFDResult file =
+ root_.MakeFile(sub_dir_path_.Append(GetRandomSuffix()));
+ EXPECT_EQ(file.second, SafeFD::Error::kNoError);
+ ASSERT_TRUE(file.first.is_valid());
+ }
+
+ // Recursively delete with a max level that is too small. Capture errno.
+ SafeFD::Error result = root_.Rmdir(kSubdirName, true /*recursive*/,
+ 1 /*max_depth*/, true /*keep_going*/);
+ int rmdir_errno = errno;
+
+ EXPECT_EQ(result, SafeFD::Error::kExceededMaximum);
+
+ // If we keep going, the last operation will be the post-order unlink of
+ // the top-level directory. This has to fail with ENOTEMPTY since we did
+ // not delete the too-deep sub-directories. This particular behavior
+ // should not be part of the API contract and this can be relaxed if the
+ // implementation is changed.
+ EXPECT_EQ(rmdir_errno, ENOTEMPTY);
+
+ // The deep directory must still exist.
+ ASSERT_TRUE(
+ base::DeleteFile(sub_dir_path_.Append(kSubdirName), false /*recursive*/));
+
+ // We cannot control the iteration order so even if we incorrectly
+ // stopped early the directory might still be empty if the deep
+ // directories were last in the iteration order. But a non-empty
+ // directory is always incorrect.
+ ASSERT_TRUE(base::IsDirectoryEmpty(sub_dir_path_));
+}
+
+TEST_F(SafeFDTest, Rmdir_Recursive_StopOnError) {
+ ASSERT_TRUE(SetupSubdir());
+
+ ASSERT_TRUE(base::CreateDirectory(sub_dir_path_.Append(kSubdirName)));
+
+ // Give us something to iterate over.
+ constexpr int kNumSentinel = 25;
+ for (int i = 0; i < kNumSentinel; i++) {
+ SafeFD::SafeFDResult file =
+ root_.MakeFile(sub_dir_path_.Append(GetRandomSuffix()));
+ EXPECT_EQ(file.second, SafeFD::Error::kNoError);
+ ASSERT_TRUE(file.first.is_valid());
+ }
+
+ // Recursively delete with a max level that is too small. Capture errno.
+ SafeFD::Error result = root_.Rmdir(kSubdirName, true /*recursive*/,
+ 1 /*max_depth*/, false /*keep_going*/);
+ int rmdir_errno = errno;
+
+ EXPECT_EQ(result, SafeFD::Error::kExceededMaximum);
+
+ // If we stop on encountering a too-deep directory, we never actually
+ // make any libc calls that encounter errors. This particular behavior
+ // should not be part of the API contract and this can be relaxed if the
+ // implementation is changed.
+ EXPECT_EQ(rmdir_errno, 0);
+
+ // The deep directory must still exist.
+ ASSERT_TRUE(
+ base::DeleteFile(sub_dir_path_.Append(kSubdirName), false /*recursive*/));
+}
+
} // namespace brillo
diff --git a/brillo/flag_helper.cc b/brillo/flag_helper.cc
index 065a1c7..1c332d3 100644
--- a/brillo/flag_helper.cc
+++ b/brillo/flag_helper.cc
@@ -86,6 +86,22 @@ const char* Int32Flag::GetType() const {
return "int";
}
+UInt32Flag::UInt32Flag(const char* name,
+ uint32_t* value,
+ const char* default_value,
+ const char* help,
+ bool visible)
+ : Flag(name, default_value, help, visible), value_(value) {
+}
+
+bool UInt32Flag::SetValue(const std::string& value) {
+ return base::StringToUint(value, value_);
+}
+
+const char* UInt32Flag::GetType() const {
+ return "uint32";
+}
+
Int64Flag::Int64Flag(const char* name,
int64_t* value,
const char* default_value,
diff --git a/brillo/flag_helper.h b/brillo/flag_helper.h
index 810a00c..c6d63cd 100644
--- a/brillo/flag_helper.h
+++ b/brillo/flag_helper.h
@@ -20,6 +20,7 @@
//
// DEFINE_bool(name, default_value, help)
// DEFINE_int32(name, default_value, help)
+// DEFINE_uint32(name, default_value, help)
// DEFINE_int64(name, default_value, help)
// DEFINE_uint64(name, default_value, help)
// DEFINE_double(name, default_value, help)
@@ -118,6 +119,21 @@ class BRILLO_EXPORT Int32Flag final : public Flag {
int* value_;
};
+class BRILLO_EXPORT UInt32Flag final : public Flag {
+ public:
+ UInt32Flag(const char* name,
+ uint32_t* value,
+ const char* default_value,
+ const char* help,
+ bool visible);
+ bool SetValue(const std::string& value) override;
+
+ const char* GetType() const override;
+
+ private:
+ uint32_t* value_;
+};
+
class BRILLO_EXPORT Int64Flag final : public Flag {
public:
Int64Flag(const char* name,
@@ -191,6 +207,8 @@ class BRILLO_EXPORT StringFlag final : public Flag {
#define DEFINE_int32(name, value, help) \
DEFINE_type(int, Int32Flag, name, value, help)
+#define DEFINE_uint32(name, value, help) \
+ DEFINE_type(uint32_t, UInt32Flag, name, value, help)
#define DEFINE_int64(name, value, help) \
DEFINE_type(int64_t, Int64Flag, name, value, help)
#define DEFINE_uint64(name, value, help) \
diff --git a/brillo/flag_helper_test.cc b/brillo/flag_helper_test.cc
index 29c6429..7c7164d 100644
--- a/brillo/flag_helper_test.cc
+++ b/brillo/flag_helper_test.cc
@@ -8,6 +8,7 @@
#include <base/command_line.h>
#include <base/macros.h>
+#include <base/stl_util.h>
#include <brillo/flag_helper.h>
#include <gtest/gtest.h>
@@ -29,6 +30,8 @@ TEST_F(FlagHelperTest, Defaults) {
DEFINE_int32(int32_1, INT32_MIN, "Test int32 flag");
DEFINE_int32(int32_2, 0, "Test int32 flag");
DEFINE_int32(int32_3, INT32_MAX, "Test int32 flag");
+ DEFINE_uint32(uint32_1, 0, "Test uint32 flag");
+ DEFINE_uint32(uint32_2, UINT32_MAX, "Test uint32 flag");
DEFINE_int64(int64_1, INT64_MIN, "Test int64 flag");
DEFINE_int64(int64_2, 0, "Test int64 flag");
DEFINE_int64(int64_3, INT64_MAX, "Test int64 flag");
@@ -41,17 +44,19 @@ TEST_F(FlagHelperTest, Defaults) {
DEFINE_string(string_2, "value", "Test string flag");
const char* argv[] = {"test_program"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestDefaultTrue");
EXPECT_TRUE(FLAGS_bool1);
EXPECT_FALSE(FLAGS_bool2);
EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
EXPECT_EQ(FLAGS_int32_2, 0);
EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
+ EXPECT_EQ(FLAGS_uint32_1, 0);
+ EXPECT_EQ(FLAGS_uint32_2, UINT32_MAX);
EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
EXPECT_EQ(FLAGS_int64_2, 0);
EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
@@ -74,6 +79,8 @@ TEST_F(FlagHelperTest, SetValueDoubleDash) {
DEFINE_int32(int32_1, 1, "Test int32 flag");
DEFINE_int32(int32_2, 1, "Test int32 flag");
DEFINE_int32(int32_3, 1, "Test int32 flag");
+ DEFINE_uint32(uint32_1, 1, "Test uint32 flag");
+ DEFINE_uint32(uint32_2, 1, "Test uint32 flag");
DEFINE_int64(int64_1, 1, "Test int64 flag");
DEFINE_int64(int64_2, 1, "Test int64 flag");
DEFINE_int64(int64_3, 1, "Test int64 flag");
@@ -93,6 +100,8 @@ TEST_F(FlagHelperTest, SetValueDoubleDash) {
"--int32_1=-2147483648",
"--int32_2=0",
"--int32_3=2147483647",
+ "--uint32_1=0",
+ "--uint32_2=4294967295",
"--int64_1=-9223372036854775808",
"--int64_2=0",
"--int64_3=9223372036854775807",
@@ -103,11 +112,11 @@ TEST_F(FlagHelperTest, SetValueDoubleDash) {
"--double_3=100.5",
"--string_1=",
"--string_2=value"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestDefaultTrue");
EXPECT_TRUE(FLAGS_bool1);
EXPECT_FALSE(FLAGS_bool2);
@@ -116,6 +125,8 @@ TEST_F(FlagHelperTest, SetValueDoubleDash) {
EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
EXPECT_EQ(FLAGS_int32_2, 0);
EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
+ EXPECT_EQ(FLAGS_uint32_1, 0);
+ EXPECT_EQ(FLAGS_uint32_2, UINT32_MAX);
EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
EXPECT_EQ(FLAGS_int64_2, 0);
EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
@@ -136,6 +147,8 @@ TEST_F(FlagHelperTest, SetValueSingleDash) {
DEFINE_int32(int32_1, 1, "Test int32 flag");
DEFINE_int32(int32_2, 1, "Test int32 flag");
DEFINE_int32(int32_3, 1, "Test int32 flag");
+ DEFINE_uint64(uint32_1, 1, "Test uint32 flag");
+ DEFINE_uint64(uint32_2, 1, "Test uint32 flag");
DEFINE_int64(int64_1, 1, "Test int64 flag");
DEFINE_int64(int64_2, 1, "Test int64 flag");
DEFINE_int64(int64_3, 1, "Test int64 flag");
@@ -153,6 +166,8 @@ TEST_F(FlagHelperTest, SetValueSingleDash) {
"-int32_1=-2147483648",
"-int32_2=0",
"-int32_3=2147483647",
+ "-uint32_1=0",
+ "-uint32_2=4294967295",
"-int64_1=-9223372036854775808",
"-int64_2=0",
"-int64_3=9223372036854775807",
@@ -163,17 +178,19 @@ TEST_F(FlagHelperTest, SetValueSingleDash) {
"-double_3=100.5",
"-string_1=",
"-string_2=value"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestDefaultTrue");
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestDefaultTrue");
EXPECT_TRUE(FLAGS_bool1);
EXPECT_FALSE(FLAGS_bool2);
EXPECT_EQ(FLAGS_int32_1, INT32_MIN);
EXPECT_EQ(FLAGS_int32_2, 0);
EXPECT_EQ(FLAGS_int32_3, INT32_MAX);
+ EXPECT_EQ(FLAGS_uint32_1, 0);
+ EXPECT_EQ(FLAGS_uint32_2, UINT32_MAX);
EXPECT_EQ(FLAGS_int64_1, INT64_MIN);
EXPECT_EQ(FLAGS_int64_2, 0);
EXPECT_EQ(FLAGS_int64_3, INT64_MAX);
@@ -192,11 +209,11 @@ TEST_F(FlagHelperTest, DuplicateSetValue) {
DEFINE_int32(int32_1, 0, "Test in32 flag");
const char* argv[] = {"test_program", "--int32_1=5", "--int32_1=10"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestDuplicateSetvalue");
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestDuplicateSetvalue");
EXPECT_EQ(FLAGS_int32_1, 10);
}
@@ -206,11 +223,11 @@ TEST_F(FlagHelperTest, FlagTerminator) {
DEFINE_int32(int32_1, 0, "Test int32 flag");
const char* argv[] = {"test_program", "--int32_1=5", "--", "--int32_1=10"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestFlagTerminator");
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestFlagTerminator");
EXPECT_EQ(FLAGS_int32_1, 5);
}
@@ -220,13 +237,14 @@ TEST_F(FlagHelperTest, FlagTerminator) {
TEST_F(FlagHelperTest, HelpMessage) {
DEFINE_bool(bool_1, true, "Test bool flag");
DEFINE_int32(int_1, 0, "Test int flag");
+ DEFINE_uint32(uint32_1, 0, "Test uint32 flag");
DEFINE_int64(int64_1, 0, "Test int64 flag");
DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
DEFINE_double(double_1, 0, "Test double flag");
DEFINE_string(string_1, "", "Test string flag");
const char* argv[] = {"test_program", "--int_1=value", "--help"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
@@ -235,7 +253,7 @@ TEST_F(FlagHelperTest, HelpMessage) {
stdout = stderr;
ASSERT_EXIT(
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestHelpMessage"),
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestHelpMessage"),
::testing::ExitedWithCode(EX_OK),
"TestHelpMessage\n\n"
" --bool_1 \\(Test bool flag\\) type: bool default: true\n"
@@ -244,6 +262,7 @@ TEST_F(FlagHelperTest, HelpMessage) {
" --int64_1 \\(Test int64 flag\\) type: int64 default: 0\n"
" --int_1 \\(Test int flag\\) type: int default: 0\n"
" --string_1 \\(Test string flag\\) type: string default: \"\"\n"
+ " --uint32_1 \\(Test uint32 flag\\) type: uint32 default: 0\n"
" --uint64_1 \\(Test uint64 flag\\) type: uint64 default: 0\n");
stdout = orig;
@@ -253,7 +272,7 @@ TEST_F(FlagHelperTest, HelpMessage) {
// to exit with EX_USAGE error code and corresponding error message.
TEST_F(FlagHelperTest, UnknownFlag) {
const char* argv[] = {"test_program", "--flag=value"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
@@ -261,7 +280,7 @@ TEST_F(FlagHelperTest, UnknownFlag) {
FILE* orig = stdout;
stdout = stderr;
- ASSERT_EXIT(brillo::FlagHelper::Init(arraysize(argv), argv, "TestIntExit"),
+ ASSERT_EXIT(brillo::FlagHelper::Init(base::size(argv), argv, "TestIntExit"),
::testing::ExitedWithCode(EX_USAGE),
"ERROR: unknown command line flag 'flag'");
@@ -274,7 +293,7 @@ TEST_F(FlagHelperTest, BoolParseError) {
DEFINE_bool(bool_1, 0, "Test bool flag");
const char* argv[] = {"test_program", "--bool_1=value"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
@@ -283,7 +302,7 @@ TEST_F(FlagHelperTest, BoolParseError) {
stdout = stderr;
ASSERT_EXIT(
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestBoolParseError"),
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestBoolParseError"),
::testing::ExitedWithCode(EX_DATAERR),
"ERROR: illegal value 'value' specified for bool flag 'bool_1'");
@@ -296,7 +315,7 @@ TEST_F(FlagHelperTest, Int32ParseError) {
DEFINE_int32(int_1, 0, "Test int flag");
const char* argv[] = {"test_program", "--int_1=value"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
@@ -304,11 +323,57 @@ TEST_F(FlagHelperTest, Int32ParseError) {
FILE* orig = stdout;
stdout = stderr;
- ASSERT_EXIT(brillo::FlagHelper::Init(arraysize(argv),
- argv,
- "TestInt32ParseError"),
- ::testing::ExitedWithCode(EX_DATAERR),
- "ERROR: illegal value 'value' specified for int flag 'int_1'");
+ ASSERT_EXIT(
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestInt32ParseError"),
+ ::testing::ExitedWithCode(EX_DATAERR),
+ "ERROR: illegal value 'value' specified for int flag 'int_1'");
+
+ stdout = orig;
+}
+
+// Test that when passing an incorrect/unparsable type to a command line flag,
+// the program exits with code EX_DATAERR and outputs a corresponding message.
+TEST_F(FlagHelperTest, Uint32ParseErrorUppperBound) {
+ DEFINE_uint32(uint32_1, 0, "Test uint32 flag");
+
+ // test with UINT32_MAX + 1
+ const char* argv[] = {"test_program", "--uint32_1=4294967296"};
+ base::CommandLine command_line(base::size(argv), argv);
+
+ brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+ &command_line);
+
+ FILE* orig = stdout;
+ stdout = stderr;
+
+ ASSERT_EXIT(
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestUint32ParseError"),
+ ::testing::ExitedWithCode(EX_DATAERR),
+ "ERROR: illegal value '4294967296' specified for uint32 flag "
+ "'uint32_1'");
+
+ stdout = orig;
+}
+
+// Test that when passing an incorrect/unparsable type to a command line flag,
+// the program exits with code EX_DATAERR and outputs a corresponding message.
+TEST_F(FlagHelperTest, Uint32ParseErrorNegativeValue) {
+ DEFINE_uint32(uint32_1, 0, "Test uint32 flag");
+
+ const char* argv[] = {"test_program", "--uint32_1=-1"};
+ base::CommandLine command_line(base::size(argv), argv);
+
+ brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
+ &command_line);
+
+ FILE* orig = stdout;
+ stdout = stderr;
+
+ ASSERT_EXIT(
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestUint32ParseError"),
+ ::testing::ExitedWithCode(EX_DATAERR),
+ "ERROR: illegal value '-1' specified for uint32 flag "
+ "'uint32_1'");
stdout = orig;
}
@@ -319,7 +384,7 @@ TEST_F(FlagHelperTest, Int64ParseError) {
DEFINE_int64(int64_1, 0, "Test int64 flag");
const char* argv[] = {"test_program", "--int64_1=value"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
@@ -328,7 +393,7 @@ TEST_F(FlagHelperTest, Int64ParseError) {
stdout = stderr;
ASSERT_EXIT(
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestInt64ParseError"),
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestInt64ParseError"),
::testing::ExitedWithCode(EX_DATAERR),
"ERROR: illegal value 'value' specified for int64 flag "
"'int64_1'");
@@ -342,7 +407,7 @@ TEST_F(FlagHelperTest, UInt64ParseError) {
DEFINE_uint64(uint64_1, 0, "Test uint64 flag");
const char* argv[] = {"test_program", "--uint64_1=value"};
- base::CommandLine command_line(arraysize(argv), argv);
+ base::CommandLine command_line(base::size(argv), argv);
brillo::FlagHelper::GetInstance()->set_command_line_for_testing(
&command_line);
@@ -351,7 +416,7 @@ TEST_F(FlagHelperTest, UInt64ParseError) {
stdout = stderr;
ASSERT_EXIT(
- brillo::FlagHelper::Init(arraysize(argv), argv, "TestUInt64ParseError"),
+ brillo::FlagHelper::Init(base::size(argv), argv, "TestUInt64ParseError"),
::testing::ExitedWithCode(EX_DATAERR),
"ERROR: illegal value 'value' specified for uint64 flag "
"'uint64_1'");
diff --git a/brillo/http/http_proxy_test.cc b/brillo/http/http_proxy_test.cc
index eb44263..a0d1bfa 100644
--- a/brillo/http/http_proxy_test.cc
+++ b/brillo/http/http_proxy_test.cc
@@ -32,23 +32,20 @@ class HttpProxyTest : public testing::Test {
public:
void ResolveProxyHandlerAsync(dbus::MethodCall* method_call,
int timeout_msec,
- dbus::ObjectProxy::ResponseCallback
- MIGRATE_WrapObjectProxyCallback(callback)) {
+ dbus::ObjectProxy::ResponseCallback* callback) {
if (null_dbus_response_) {
- std::move(MIGRATE_WrapObjectProxyCallback(callback)).Run(nullptr);
+ std::move(*callback).Run(nullptr);
return;
}
- std::move(MIGRATE_WrapObjectProxyCallback(callback))
- .Run(CreateDBusResponse(method_call).get());
+ std::move(*callback).Run(CreateDBusResponse(method_call).get());
}
- MIGRATE_WrapObjectProxyResponseType(dbus::Response)
- ResolveProxyHandler(dbus::MethodCall* method_call, int timeout_msec) {
+ std::unique_ptr<dbus::Response> ResolveProxyHandler(
+ dbus::MethodCall* method_call, int timeout_msec) {
if (null_dbus_response_) {
- return MIGRATE_WrapObjectProxyResponseEmpty;
+ return std::unique_ptr<dbus::Response>();
}
- return MIGRATE_WrapObjectProxyResponseConversion(
- CreateDBusResponse(method_call));
+ return CreateDBusResponse(method_call);
}
MOCK_METHOD(void,
@@ -102,7 +99,7 @@ class HttpProxyTest : public testing::Test {
TEST_F(HttpProxyTest, DBusNullResponseFails) {
std::vector<std::string> proxies;
null_dbus_response_ = true;
- EXPECT_CALL(*object_proxy_, MIGRATE_MockCallMethodAndBlock(_, _))
+ EXPECT_CALL(*object_proxy_, CallMethodAndBlock(_, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler));
EXPECT_FALSE(GetChromeProxyServers(bus_, kTestUrl, &proxies));
}
@@ -110,14 +107,14 @@ TEST_F(HttpProxyTest, DBusNullResponseFails) {
TEST_F(HttpProxyTest, DBusInvalidResponseFails) {
std::vector<std::string> proxies;
invalid_dbus_response_ = true;
- EXPECT_CALL(*object_proxy_, MIGRATE_MockCallMethodAndBlock(_, _))
+ EXPECT_CALL(*object_proxy_, CallMethodAndBlock(_, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler));
EXPECT_FALSE(GetChromeProxyServers(bus_, kTestUrl, &proxies));
}
TEST_F(HttpProxyTest, NoProxies) {
std::vector<std::string> proxies;
- EXPECT_CALL(*object_proxy_, MIGRATE_MockCallMethodAndBlock(_, _))
+ EXPECT_CALL(*object_proxy_, CallMethodAndBlock(_, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler));
EXPECT_TRUE(GetChromeProxyServers(bus_, kTestUrl, &proxies));
EXPECT_THAT(proxies, ElementsAre(kDirectProxy));
@@ -126,7 +123,7 @@ TEST_F(HttpProxyTest, NoProxies) {
TEST_F(HttpProxyTest, MultipleProxiesWithoutDirect) {
proxy_info_ = "proxy example.com; socks5 foo.com;";
std::vector<std::string> proxies;
- EXPECT_CALL(*object_proxy_, MIGRATE_MockCallMethodAndBlock(_, _))
+ EXPECT_CALL(*object_proxy_, CallMethodAndBlock(_, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler));
EXPECT_TRUE(GetChromeProxyServers(bus_, kTestUrl, &proxies));
EXPECT_THAT(proxies, ElementsAre("http://example.com", "socks5://foo.com",
@@ -137,7 +134,7 @@ TEST_F(HttpProxyTest, MultipleProxiesWithDirect) {
proxy_info_ = "socks foo.com; Https example.com ; badproxy example2.com ; "
"socks5 test.com ; proxy foobar.com; DIRECT ";
std::vector<std::string> proxies;
- EXPECT_CALL(*object_proxy_, MIGRATE_MockCallMethodAndBlock(_, _))
+ EXPECT_CALL(*object_proxy_, CallMethodAndBlock(_, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandler));
EXPECT_TRUE(GetChromeProxyServers(bus_, kTestUrl, &proxies));
EXPECT_THAT(proxies, ElementsAre("socks4://foo.com", "https://example.com",
@@ -147,7 +144,7 @@ TEST_F(HttpProxyTest, MultipleProxiesWithDirect) {
TEST_F(HttpProxyTest, DBusNullResponseFailsAsync) {
null_dbus_response_ = true;
- EXPECT_CALL(*object_proxy_, MIGRATE_CallMethod(_, _, _))
+ EXPECT_CALL(*object_proxy_, DoCallMethod(_, _, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandlerAsync));
EXPECT_CALL(*this, GetProxiesCallback(false, _));
GetChromeProxyServersAsync(
@@ -157,7 +154,7 @@ TEST_F(HttpProxyTest, DBusNullResponseFailsAsync) {
TEST_F(HttpProxyTest, DBusInvalidResponseFailsAsync) {
invalid_dbus_response_ = true;
- EXPECT_CALL(*object_proxy_, MIGRATE_CallMethod(_, _, _))
+ EXPECT_CALL(*object_proxy_, DoCallMethod(_, _, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandlerAsync));
EXPECT_CALL(*this, GetProxiesCallback(false, _));
GetChromeProxyServersAsync(
@@ -173,7 +170,7 @@ TEST_F(HttpProxyTest, MultipleProxiesWithDirectAsync) {
std::vector<std::string> expected = {
"socks4://foo.com", "https://example.com", "socks5://test.com",
"http://foobar.com", kDirectProxy};
- EXPECT_CALL(*object_proxy_, MIGRATE_CallMethod(_, _, _))
+ EXPECT_CALL(*object_proxy_, DoCallMethod(_, _, _))
.WillOnce(Invoke(this, &HttpProxyTest::ResolveProxyHandlerAsync));
EXPECT_CALL(*this, GetProxiesCallback(true, expected));
GetChromeProxyServersAsync(
diff --git a/brillo/http/http_transport_curl.cc b/brillo/http/http_transport_curl.cc
index 45a28a3..de6899a 100644
--- a/brillo/http/http_transport_curl.cc
+++ b/brillo/http/http_transport_curl.cc
@@ -7,10 +7,11 @@
#include <limits>
#include <base/bind.h>
+#include <base/files/file_descriptor_watcher_posix.h>
#include <base/files/file_util.h>
#include <base/logging.h>
-#include <base/message_loop/message_loop.h>
#include <base/strings/stringprintf.h>
+#include <base/threading/thread_task_runner_handle.h>
#include <brillo/http/http_connection_curl.h>
#include <brillo/http/http_request.h>
#include <brillo/strings/string_utils.h>
@@ -22,7 +23,7 @@ namespace curl {
// This is a class that stores connection data on particular CURL socket
// and provides file descriptor watcher to monitor read and/or write operations
// on the socket's file descriptor.
-class Transport::SocketPollData : public base::MessagePumpForIO::FdWatcher {
+class Transport::SocketPollData {
public:
SocketPollData(const std::shared_ptr<CurlInterface>& curl_interface,
CURLM* curl_multi_handle,
@@ -31,27 +32,35 @@ class Transport::SocketPollData : public base::MessagePumpForIO::FdWatcher {
: curl_interface_(curl_interface),
curl_multi_handle_(curl_multi_handle),
transport_(transport),
- socket_fd_(socket_fd),
- file_descriptor_watcher_(FROM_HERE) {}
+ socket_fd_(socket_fd) {}
- // Returns the pointer for the socket-specific file descriptor watcher.
- base::MessagePumpForIO::FdWatchController* GetWatcher() {
- return &file_descriptor_watcher_;
+ void StopWatcher() {
+ read_watcher_ = nullptr;
+ write_watcher_ = nullptr;
}
- private:
- // Overrides from base::MessagePumpForIO::Watcher.
- void OnFileCanReadWithoutBlocking(int fd) override {
- OnSocketReady(fd, CURL_CSELECT_IN);
+ bool WatchReadable() {
+ read_watcher_ = base::FileDescriptorWatcher::WatchReadable(
+ socket_fd_,
+ base::BindRepeating(&Transport::SocketPollData::OnSocketReady,
+ base::Unretained(this),
+ CURL_CSELECT_IN));
+ return read_watcher_.get();
}
- void OnFileCanWriteWithoutBlocking(int fd) override {
- OnSocketReady(fd, CURL_CSELECT_OUT);
+
+ bool WatchWritable() {
+ write_watcher_ = base::FileDescriptorWatcher::WatchWritable(
+ socket_fd_,
+ base::BindRepeating(&Transport::SocketPollData::OnSocketReady,
+ base::Unretained(this),
+ CURL_CSELECT_OUT));
+ return write_watcher_.get();
}
+ private:
// Data on the socket is available to be read from or written to.
// Notify CURL of the action it needs to take on the socket file descriptor.
- void OnSocketReady(int fd, int action) {
- CHECK_EQ(socket_fd_, fd) << "Unexpected socket file descriptor";
+ void OnSocketReady(int action) {
int still_running_count = 0;
CURLMcode code = curl_interface_->MultiSocketAction(
curl_multi_handle_, socket_fd_, action, &still_running_count);
@@ -70,8 +79,9 @@ class Transport::SocketPollData : public base::MessagePumpForIO::FdWatcher {
Transport* transport_;
// The socket file descriptor for the connection.
curl_socket_t socket_fd_;
- // File descriptor watcher to notify us of asynchronous I/O on the FD.
- base::MessagePumpForIO::FdWatchController file_descriptor_watcher_;
+
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> read_watcher_;
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> write_watcher_;
DISALLOW_COPY_AND_ASSIGN(SocketPollData);
};
@@ -212,8 +222,7 @@ std::shared_ptr<http::Connection> Transport::CreateConnection(
void Transport::RunCallbackAsync(const base::Location& from_here,
const base::Closure& callback) {
- base::MessageLoopForIO::current()->task_runner()->PostTask(
- from_here, callback);
+ base::ThreadTaskRunnerHandle::Get()->PostTask(from_here, callback);
}
RequestID Transport::StartAsyncTransfer(http::Connection* connection,
@@ -386,42 +395,22 @@ int Transport::MultiSocketCallback(CURL* easy,
// Make sure we stop watching the socket file descriptor now, before
// we schedule the SocketPollData for deletion.
- poll_data->GetWatcher()->StopWatchingFileDescriptor();
+ poll_data->StopWatcher();
// This method can be called indirectly from SocketPollData::OnSocketReady,
// so delay destruction of SocketPollData object till the next loop cycle.
- base::MessageLoopForIO::current()->task_runner()->DeleteSoon(FROM_HERE,
- poll_data);
+ base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, poll_data);
return 0;
}
- base::MessagePumpForIO::Mode watch_mode = base::MessagePumpForIO::WATCH_READ;
- switch (what) {
- case CURL_POLL_IN:
- watch_mode = base::MessagePumpForIO::WATCH_READ;
- break;
- case CURL_POLL_OUT:
- watch_mode = base::MessagePumpForIO::WATCH_WRITE;
- break;
- case CURL_POLL_INOUT:
- watch_mode = base::MessagePumpForIO::WATCH_READ_WRITE;
- break;
- default:
- LOG(FATAL) << "Unknown CURL socket action: " << what;
- break;
- }
+ poll_data->StopWatcher();
+
+ bool success = true;
+ if (what == CURL_POLL_IN || what == CURL_POLL_INOUT)
+ success = poll_data->WatchReadable() && success;
+ if (what == CURL_POLL_OUT || what == CURL_POLL_INOUT)
+ success = poll_data->WatchWritable() && success;
- // WatchFileDescriptor() can be called with the same controller object
- // (watcher) to amend the watch mode, however this has cumulative effect.
- // For example, if we were watching a file descriptor for READ operations
- // and now call it to watch for WRITE, it will end up watching for both
- // READ and WRITE. This is not what we want here, so stop watching the
- // file descriptor on previous controller before starting with a different
- // mode.
- if (!poll_data->GetWatcher()->StopWatchingFileDescriptor())
- LOG(WARNING) << "Failed to stop watching the previous socket descriptor";
- CHECK(base::MessageLoopForIO::current()->WatchFileDescriptor(
- s, true, watch_mode, poll_data->GetWatcher(), poll_data))
- << "Failed to watch the CURL socket.";
+ CHECK(success) << "Failed to watch the CURL socket.";
return 0;
}
@@ -433,11 +422,11 @@ int Transport::MultiTimerCallback(CURLM* /* multi */,
// Cancel any previous timer callbacks.
transport->weak_ptr_factory_for_timer_.InvalidateWeakPtrs();
if (timeout_ms >= 0) {
- base::MessageLoopForIO::current()->task_runner()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&Transport::OnTimer,
- transport->weak_ptr_factory_for_timer_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(timeout_ms));
+ base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&Transport::OnTimer,
+ transport->weak_ptr_factory_for_timer_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(timeout_ms));
}
return 0;
}
diff --git a/brillo/http/http_transport_curl_test.cc b/brillo/http/http_transport_curl_test.cc
index 40ef23e..6e94978 100644
--- a/brillo/http/http_transport_curl_test.cc
+++ b/brillo/http/http_transport_curl_test.cc
@@ -8,6 +8,7 @@
#include <base/bind.h>
#include <base/message_loop/message_loop.h>
#include <base/run_loop.h>
+#include <base/threading/thread_task_runner_handle.h>
#include <brillo/http/http_connection_curl.h>
#include <brillo/http/http_request.h>
#include <brillo/http/mock_curl_api.h>
@@ -242,7 +243,7 @@ TEST_F(HttpCurlTransportAsyncTest, StartAsyncTransfer) {
auto success_callback = base::Bind([](
int* success_call_count, const base::Closure& quit_closure,
RequestID /* request_id */, std::unique_ptr<http::Response> /* resp */) {
- base::MessageLoop::current()->task_runner()->PostTask(
+ base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, quit_closure);
(*success_call_count)++;
}, &success_call_count, run_loop.QuitClosure());
diff --git a/brillo/message_loops/base_message_loop.cc b/brillo/message_loops/base_message_loop.cc
index 9a9e43f..c3499ab 100644
--- a/brillo/message_loops/base_message_loop.cc
+++ b/brillo/message_loops/base_message_loop.cc
@@ -30,12 +30,11 @@
#include <base/run_loop.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/string_split.h>
+#include <base/threading/thread_task_runner_handle.h>
#include <brillo/location_logging.h>
#include <brillo/strings/string_utils.h>
-using base::Closure;
-
namespace {
const char kMiscMinorPath[] = "/proc/misc";
@@ -49,7 +48,7 @@ const int BaseMessageLoop::kInvalidMinor = -1;
const int BaseMessageLoop::kUninitializedMinor = -2;
BaseMessageLoop::BaseMessageLoop() {
- CHECK(!base::MessageLoop::current())
+ CHECK(!base::ThreadTaskRunnerHandle::IsSet())
<< "You can't create a base::MessageLoopForIO when another "
"base::MessageLoop is already created for this thread.";
owned_base_loop_.reset(new base::MessageLoopForIO());
@@ -62,13 +61,6 @@ BaseMessageLoop::BaseMessageLoop(base::MessageLoopForIO* base_loop)
watcher_(std::make_unique<base::FileDescriptorWatcher>(base_loop_)) {}
BaseMessageLoop::~BaseMessageLoop() {
- for (auto& io_task : io_tasks_) {
- DVLOG_LOC(io_task.second.location(), 1)
- << "Removing file descriptor watcher task_id " << io_task.first
- << " leaked on BaseMessageLoop, scheduled from this location.";
- io_task.second.StopWatching();
- }
-
// Note all pending canceled delayed tasks when destroying the message loop.
size_t lazily_deleted_tasks = 0;
for (const auto& delayed_task : delayed_tasks_) {
@@ -87,85 +79,21 @@ BaseMessageLoop::~BaseMessageLoop() {
MessageLoop::TaskId BaseMessageLoop::PostDelayedTask(
const base::Location& from_here,
- const Closure &task,
+ base::OnceClosure task,
base::TimeDelta delay) {
TaskId task_id = NextTaskId();
bool base_scheduled = base_loop_->task_runner()->PostDelayedTask(
from_here,
- base::Bind(&BaseMessageLoop::OnRanPostedTask,
- weak_ptr_factory_.GetWeakPtr(),
- task_id),
+ base::BindOnce(&BaseMessageLoop::OnRanPostedTask,
+ weak_ptr_factory_.GetWeakPtr(), task_id),
delay);
DVLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << task_id
<< " to run in " << delay << ".";
if (!base_scheduled)
return MessageLoop::kTaskIdNull;
- delayed_tasks_.emplace(task_id, DelayedTask{from_here, task_id, task});
- return task_id;
-}
-
-MessageLoop::TaskId BaseMessageLoop::WatchFileDescriptor(
- const base::Location& from_here,
- int fd,
- WatchMode mode,
- bool persistent,
- const Closure &task) {
- // base::MessageLoopForIO CHECKS that "fd >= 0", so we handle that case here.
- if (fd < 0)
- return MessageLoop::kTaskIdNull;
-
- base::MessagePumpForIO::Mode base_mode = base::MessagePumpForIO::WATCH_READ;
- switch (mode) {
- case MessageLoop::kWatchRead:
- base_mode = base::MessagePumpForIO::WATCH_READ;
- break;
- case MessageLoop::kWatchWrite:
- base_mode = base::MessagePumpForIO::WATCH_WRITE;
- break;
- default:
- return MessageLoop::kTaskIdNull;
- }
-
- TaskId task_id = NextTaskId();
- auto it_bool = io_tasks_.emplace(
- std::piecewise_construct,
- std::forward_as_tuple(task_id),
- std::forward_as_tuple(
- from_here, this, task_id, fd, base_mode, persistent, task));
- // This should always insert a new element.
- DCHECK(it_bool.second);
- bool scheduled = it_bool.first->second.StartWatching();
- DVLOG_LOC(from_here, 1)
- << "Watching fd " << fd << " for "
- << (mode == MessageLoop::kWatchRead ? "reading" : "writing")
- << (persistent ? " persistently" : " just once")
- << " as task_id " << task_id
- << (scheduled ? " successfully" : " failed.");
-
- if (!scheduled) {
- io_tasks_.erase(task_id);
- return MessageLoop::kTaskIdNull;
- }
-
-#ifndef __ANDROID_HOST__
- // Determine if the passed fd is the binder file descriptor. For that, we need
- // to check that is a special char device and that the major and minor device
- // numbers match. The binder file descriptor can't be removed and added back
- // to an epoll group when there's work available to be done by the file
- // descriptor due to bugs in the binder driver (b/26524111) when used with
- // epoll. Therefore, we flag the binder fd and never attempt to remove it.
- // This may cause the binder file descriptor to be attended with higher
- // priority and cause starvation of other events.
- struct stat buf;
- if (fstat(fd, &buf) == 0 &&
- S_ISCHR(buf.st_mode) &&
- major(buf.st_rdev) == MISC_MAJOR &&
- minor(buf.st_rdev) == GetBinderMinor()) {
- it_bool.first->second.RunImmediately();
- }
-#endif
-
+ delayed_tasks_.emplace(task_id,
+ DelayedTask{from_here, task_id, std::move(task)});
return task_id;
}
@@ -173,13 +101,9 @@ bool BaseMessageLoop::CancelTask(TaskId task_id) {
if (task_id == kTaskIdNull)
return false;
auto delayed_task_it = delayed_tasks_.find(task_id);
- if (delayed_task_it == delayed_tasks_.end()) {
- // This might be an IOTask then.
- auto io_task_it = io_tasks_.find(task_id);
- if (io_task_it == io_tasks_.end())
- return false;
- return io_task_it->second.CancelTask();
- }
+ if (delayed_task_it == delayed_tasks_.end())
+ return false;
+
// A DelayedTask was found for this task_id at this point.
// Check if the callback was already canceled but we have the entry in
@@ -189,10 +113,10 @@ bool BaseMessageLoop::CancelTask(TaskId task_id) {
DVLOG_LOC(delayed_task_it->second.location, 1)
<< "Removing task_id " << task_id << " scheduled from this location.";
- // We reset to closure to a null Closure to release all the resources
+ // We reset to closure to a null OnceClosure to release all the resources
// used by this closure at this point, but we don't remove the task_id from
// delayed_tasks_ since we can't tell base::MessageLoopForIO to not run it.
- delayed_task_it->second.closure = Closure();
+ delayed_task_it->second.closure.Reset();
return true;
}
@@ -229,7 +153,7 @@ void BaseMessageLoop::BreakLoop() {
base_run_loop_->Quit();
}
-Closure BaseMessageLoop::QuitClosure() const {
+base::RepeatingClosure BaseMessageLoop::QuitClosure() const {
if (base_run_loop_ == nullptr)
return base::DoNothing();
return base_run_loop_->QuitClosure();
@@ -241,8 +165,7 @@ MessageLoop::TaskId BaseMessageLoop::NextTaskId() {
res = ++last_id_;
// We would run out of memory before we run out of task ids.
} while (!res ||
- delayed_tasks_.find(res) != delayed_tasks_.end() ||
- io_tasks_.find(res) != io_tasks_.end());
+ delayed_tasks_.find(res) != delayed_tasks_.end());
return res;
}
@@ -255,9 +178,7 @@ void BaseMessageLoop::OnRanPostedTask(MessageLoop::TaskId task_id) {
<< " scheduled from this location.";
// Mark the task as canceled while we are running it so CancelTask returns
// false.
- Closure closure = std::move(task_it->second.closure);
- task_it->second.closure = Closure();
- closure.Run();
+ std::move(task_it->second.closure).Run();
// If the |run_once_| flag is set, it is because we are instructed to run
// only once callback.
@@ -269,15 +190,6 @@ void BaseMessageLoop::OnRanPostedTask(MessageLoop::TaskId task_id) {
delayed_tasks_.erase(task_it);
}
-void BaseMessageLoop::OnFileReadyPostedTask(MessageLoop::TaskId task_id) {
- auto task_it = io_tasks_.find(task_id);
- // Even if this task was canceled while we were waiting in the message loop
- // for this method to run, the entry in io_tasks_ should still be present, but
- // won't do anything.
- DCHECK(task_it != io_tasks_.end());
- task_it->second.OnFileReadyPostedTask();
-}
-
int BaseMessageLoop::ParseBinderMinor(
const std::string& file_contents) {
int result = kInvalidMinor;
@@ -311,141 +223,4 @@ unsigned int BaseMessageLoop::GetBinderMinor() {
return binder_minor_;
}
-BaseMessageLoop::IOTask::IOTask(const base::Location& location,
- BaseMessageLoop* loop,
- MessageLoop::TaskId task_id,
- int fd,
- base::MessagePumpForIO::Mode base_mode,
- bool persistent,
- const Closure& task)
- : location_(location), loop_(loop), task_id_(task_id),
- fd_(fd), base_mode_(base_mode), persistent_(persistent), closure_(task),
- fd_watcher_(FROM_HERE) {}
-
-bool BaseMessageLoop::IOTask::StartWatching() {
- // Please see MessagePumpLibevent for definition.
- static_assert(std::is_same<base::MessagePumpForIO, base::MessagePumpLibevent>::value,
- "MessagePumpForIO::WatchFileDescriptor is not supported "
- "when MessagePumpForIO is not a MessagePumpLibevent.");
-
- return static_cast<base::MessagePumpLibevent*>(
- loop_->base_loop_->pump_.get())->WatchFileDescriptor(
- fd_, persistent_, base_mode_, &fd_watcher_, this);
-}
-
-void BaseMessageLoop::IOTask::StopWatching() {
- // This is safe to call even if we are not watching for it.
- fd_watcher_.StopWatchingFileDescriptor();
-}
-
-void BaseMessageLoop::IOTask::OnFileCanReadWithoutBlocking(int /* fd */) {
- OnFileReady();
-}
-
-void BaseMessageLoop::IOTask::OnFileCanWriteWithoutBlocking(int /* fd */) {
- OnFileReady();
-}
-
-void BaseMessageLoop::IOTask::OnFileReady() {
- // For file descriptors marked with the immediate_run flag, we don't call
- // StopWatching() and wait, instead we dispatch the callback immediately.
- if (immediate_run_) {
- posted_task_pending_ = true;
- OnFileReadyPostedTask();
- return;
- }
-
- // When the file descriptor becomes available we stop watching for it and
- // schedule a task to run the callback from the main loop. The callback will
- // run using the same scheduler used to run other delayed tasks, avoiding
- // starvation of the available posted tasks if there are file descriptors
- // always available. The new posted task will use the same TaskId as the
- // current file descriptor watching task an could be canceled in either state,
- // when waiting for the file descriptor or waiting in the main loop.
- StopWatching();
- bool base_scheduled = loop_->base_loop_->task_runner()->PostTask(
- location_,
- base::Bind(&BaseMessageLoop::OnFileReadyPostedTask,
- loop_->weak_ptr_factory_.GetWeakPtr(),
- task_id_));
- posted_task_pending_ = true;
- if (base_scheduled) {
- DVLOG_LOC(location_, 1)
- << "Dispatching task_id " << task_id_ << " for "
- << (base_mode_ == base::MessagePumpForIO::WATCH_READ ?
- "reading" : "writing")
- << " file descriptor " << fd_ << ", scheduled from this location.";
- } else {
- // In the rare case that PostTask() fails, we fall back to run it directly.
- // This would indicate a bigger problem with the message loop setup.
- LOG(ERROR) << "Error on base::MessageLoopForIO::PostTask().";
- OnFileReadyPostedTask();
- }
-}
-
-void BaseMessageLoop::IOTask::OnFileReadyPostedTask() {
- // We can't access |this| after running the |closure_| since it could call
- // CancelTask on its own task_id, so we copy the members we need now.
- BaseMessageLoop* loop_ptr = loop_;
- DCHECK(posted_task_pending_ = true);
- posted_task_pending_ = false;
-
- // If this task was already canceled, the closure will be null and there is
- // nothing else to do here. This execution doesn't count a step for RunOnce()
- // unless we have a callback to run.
- if (closure_.is_null()) {
- loop_->io_tasks_.erase(task_id_);
- return;
- }
-
- DVLOG_LOC(location_, 1)
- << "Running task_id " << task_id_ << " for "
- << (base_mode_ == base::MessagePumpForIO::WATCH_READ ?
- "reading" : "writing")
- << " file descriptor " << fd_ << ", scheduled from this location.";
-
- if (persistent_) {
- // In the persistent case we just run the callback. If this callback cancels
- // the task id, we can't access |this| anymore, so we re-start watching the
- // file descriptor before running the callback, unless this is a fd where
- // we didn't stop watching the file descriptor when it became available.
- if (!immediate_run_)
- StartWatching();
- closure_.Run();
- } else {
- // This will destroy |this|, the fd_watcher and therefore stop watching this
- // file descriptor.
- Closure closure_copy = std::move(closure_);
- loop_->io_tasks_.erase(task_id_);
- // Run the closure from the local copy we just made.
- closure_copy.Run();
- }
-
- if (loop_ptr->run_once_) {
- loop_ptr->run_once_ = false;
- loop_ptr->BreakLoop();
- }
-}
-
-bool BaseMessageLoop::IOTask::CancelTask() {
- if (closure_.is_null())
- return false;
-
- DVLOG_LOC(location_, 1)
- << "Removing task_id " << task_id_ << " scheduled from this location.";
-
- if (!posted_task_pending_) {
- // Destroying the FileDescriptorWatcher implicitly stops watching the file
- // descriptor. This will delete our instance.
- loop_->io_tasks_.erase(task_id_);
- return true;
- }
- // The IOTask is waiting for the message loop to run its delayed task, so
- // it is not watching for the file descriptor. We release the closure
- // resources now but keep the IOTask instance alive while we wait for the
- // callback to run and delete the IOTask.
- closure_ = Closure();
- return true;
-}
-
} // namespace brillo
diff --git a/brillo/message_loops/base_message_loop.h b/brillo/message_loops/base_message_loop.h
index c038ac7..75e4361 100644
--- a/brillo/message_loops/base_message_loop.h
+++ b/brillo/message_loops/base_message_loop.h
@@ -42,15 +42,9 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// MessageLoop overrides.
TaskId PostDelayedTask(const base::Location& from_here,
- const base::Closure& task,
+ base::OnceClosure task,
base::TimeDelta delay) override;
using MessageLoop::PostDelayedTask;
- TaskId WatchFileDescriptor(const base::Location& from_here,
- int fd,
- WatchMode mode,
- bool persistent,
- const base::Closure& task) override;
- using MessageLoop::WatchFileDescriptor;
bool CancelTask(TaskId task_id) override;
bool RunOnce(bool may_block) override;
void Run() override;
@@ -58,7 +52,7 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// Returns a callback that will quit the current message loop. If the message
// loop is not running, an empty (null) callback is returned.
- base::Closure QuitClosure() const;
+ base::RepeatingClosure QuitClosure() const;
private:
FRIEND_TEST(BaseMessageLoopTest, ParseBinderMinor);
@@ -75,12 +69,6 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// scheduled with Post*Task() of id |task_id|, even if it was canceled.
void OnRanPostedTask(MessageLoop::TaskId task_id);
- // Called from the message loop when the IOTask should run the scheduled
- // callback. This is a simple wrapper of IOTask::OnFileReadyPostedTask()
- // posted from the BaseMessageLoop so it is deleted when the BaseMessageLoop
- // goes out of scope since we can't cancel the callback otherwise.
- void OnFileReadyPostedTask(MessageLoop::TaskId task_id);
-
// Return a new unused task_id.
TaskId NextTaskId();
@@ -91,69 +79,7 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
base::Location location;
MessageLoop::TaskId task_id;
- base::Closure closure;
- };
-
- class IOTask : public base::MessagePumpForIO::FdWatcher {
- public:
- IOTask(const base::Location& location,
- BaseMessageLoop* loop,
- MessageLoop::TaskId task_id,
- int fd,
- base::MessagePumpForIO::Mode base_mode,
- bool persistent,
- const base::Closure& task);
-
- const base::Location& location() const { return location_; }
-
- // Used to start/stop watching the file descriptor while keeping the
- // IOTask entry available.
- bool StartWatching();
- void StopWatching();
-
- // Called from the message loop as a PostTask() when the file descriptor is
- // available, scheduled to run from OnFileReady().
- void OnFileReadyPostedTask();
-
- // Cancel the IOTask and returns whether it was actually canceled, with the
- // same semantics as MessageLoop::CancelTask().
- bool CancelTask();
-
- // Sets the closure to be run immediately whenever the file descriptor
- // becomes ready.
- void RunImmediately() { immediate_run_ = true; }
-
- private:
- base::Location location_;
- BaseMessageLoop* loop_;
-
- // These are the arguments passed in the constructor, basically forwarding
- // all the arguments passed to WatchFileDescriptor() plus the assigned
- // TaskId for this task.
- MessageLoop::TaskId task_id_;
- int fd_;
- base::MessagePumpForIO::Mode base_mode_;
- bool persistent_;
- base::Closure closure_;
-
- base::MessagePumpForIO::FdWatchController fd_watcher_;
-
- // Tells whether there is a pending call to OnFileReadPostedTask().
- bool posted_task_pending_{false};
-
- // Whether the registered callback should be running immediately when the
- // file descriptor is ready, as opposed to posting a task to the main loop
- // to prevent starvation.
- bool immediate_run_{false};
-
- // base::MessageLoopForIO::Watcher overrides:
- void OnFileCanReadWithoutBlocking(int fd) override;
- void OnFileCanWriteWithoutBlocking(int fd) override;
-
- // Common implementation for both the read and write case.
- void OnFileReady();
-
- DISALLOW_COPY_AND_ASSIGN(IOTask);
+ base::OnceClosure closure;
};
// The base::MessageLoopForIO instance owned by this class, if any. This
@@ -163,9 +89,6 @@ class BRILLO_EXPORT BaseMessageLoop : public MessageLoop {
// Tasks blocked on a timeout.
std::map<MessageLoop::TaskId, DelayedTask> delayed_tasks_;
- // Tasks blocked on I/O.
- std::map<MessageLoop::TaskId, IOTask> io_tasks_;
-
// Flag to mark that we should run the message loop only one iteration.
bool run_once_{false};
diff --git a/brillo/message_loops/fake_message_loop.cc b/brillo/message_loops/fake_message_loop.cc
index 41f5b51..185b20c 100644
--- a/brillo/message_loops/fake_message_loop.cc
+++ b/brillo/message_loops/fake_message_loop.cc
@@ -15,7 +15,7 @@ FakeMessageLoop::FakeMessageLoop(base::SimpleTestClock* clock)
MessageLoop::TaskId FakeMessageLoop::PostDelayedTask(
const base::Location& from_here,
- const base::Closure& task,
+ base::OnceClosure task,
base::TimeDelta delay) {
// If no SimpleTestClock was provided, we use the last time we fired a
// callback. In this way, tasks scheduled from a Closure will have the right
@@ -25,7 +25,7 @@ MessageLoop::TaskId FakeMessageLoop::PostDelayedTask(
MessageLoop::TaskId current_id = ++last_id_;
// FakeMessageLoop is limited to only 2^64 tasks. That should be enough.
CHECK(current_id);
- tasks_.emplace(current_id, ScheduledTask{from_here, false, task});
+ tasks_.emplace(current_id, ScheduledTask{from_here, std::move(task)});
fire_order_.push(std::make_pair(current_time_ + delay, current_id));
VLOG_LOC(from_here, 1) << "Scheduling delayed task_id " << current_id
<< " to run at " << current_time_ + delay
@@ -33,20 +33,6 @@ MessageLoop::TaskId FakeMessageLoop::PostDelayedTask(
return current_id;
}
-MessageLoop::TaskId FakeMessageLoop::WatchFileDescriptor(
- const base::Location& from_here,
- int fd,
- WatchMode mode,
- bool persistent,
- const base::Closure& task) {
- MessageLoop::TaskId current_id = ++last_id_;
- // FakeMessageLoop is limited to only 2^64 tasks. That should be enough.
- CHECK(current_id);
- tasks_.emplace(current_id, ScheduledTask{from_here, persistent, task});
- fds_watched_.emplace(std::make_pair(fd, mode), current_id);
- return current_id;
-}
-
bool FakeMessageLoop::CancelTask(TaskId task_id) {
if (task_id == MessageLoop::kTaskIdNull)
return false;
@@ -58,36 +44,6 @@ bool FakeMessageLoop::CancelTask(TaskId task_id) {
bool FakeMessageLoop::RunOnce(bool may_block) {
if (test_clock_)
current_time_ = test_clock_->Now();
- // Try to fire ready file descriptors first.
- for (const auto& fd_mode : fds_ready_) {
- const auto& fd_watched = fds_watched_.find(fd_mode);
- if (fd_watched == fds_watched_.end())
- continue;
- // The fd_watched->second task might have been canceled and we never removed
- // it from the fds_watched_, so we fix that now.
- const auto& scheduled_task_ref = tasks_.find(fd_watched->second);
- if (scheduled_task_ref == tasks_.end()) {
- fds_watched_.erase(fd_watched);
- continue;
- }
- VLOG_LOC(scheduled_task_ref->second.location, 1)
- << "Running task_id " << fd_watched->second
- << " for watching file descriptor " << fd_mode.first << " for "
- << (fd_mode.second == MessageLoop::kWatchRead ? "reading" : "writing")
- << (scheduled_task_ref->second.persistent ?
- " persistently" : " just once")
- << " scheduled from this location.";
- if (scheduled_task_ref->second.persistent) {
- scheduled_task_ref->second.callback.Run();
- } else {
- base::Closure callback = std::move(scheduled_task_ref->second.callback);
- tasks_.erase(scheduled_task_ref);
- fds_watched_.erase(fd_watched);
- callback.Run();
- }
- return true;
- }
-
// Try to fire time-based callbacks afterwards.
while (!fire_order_.empty() &&
(may_block || fire_order_.top().first <= current_time_)) {
@@ -108,32 +64,22 @@ bool FakeMessageLoop::RunOnce(bool may_block) {
// Move the Closure out of the map before delete it. We need to delete the
// entry from the map before we call the callback, since calling CancelTask
// for the task you are running now should fail and return false.
- base::Closure callback = std::move(scheduled_task_ref->second.callback);
+ base::OnceClosure callback = std::move(scheduled_task_ref->second.callback);
VLOG_LOC(scheduled_task_ref->second.location, 1)
<< "Running task_id " << task_ref.second
<< " at time " << current_time_ << " from this location.";
tasks_.erase(scheduled_task_ref);
- callback.Run();
+ std::move(callback).Run();
return true;
}
return false;
}
-void FakeMessageLoop::SetFileDescriptorReadiness(int fd,
- WatchMode mode,
- bool ready) {
- if (ready)
- fds_ready_.emplace(fd, mode);
- else
- fds_ready_.erase(std::make_pair(fd, mode));
-}
-
bool FakeMessageLoop::PendingTasks() {
for (const auto& task : tasks_) {
VLOG_LOC(task.second.location, 1)
- << "Pending " << (task.second.persistent ? "persistent " : "")
- << "task_id " << task.first << " scheduled from here.";
+ << "Pending task_id " << task.first << " scheduled from here.";
}
return !tasks_.empty();
}
diff --git a/brillo/message_loops/fake_message_loop.h b/brillo/message_loops/fake_message_loop.h
index 4b6e8ac..783af1b 100644
--- a/brillo/message_loops/fake_message_loop.h
+++ b/brillo/message_loops/fake_message_loop.h
@@ -37,26 +37,14 @@ class BRILLO_EXPORT FakeMessageLoop : public MessageLoop {
~FakeMessageLoop() override = default;
TaskId PostDelayedTask(const base::Location& from_here,
- const base::Closure& task,
+ base::OnceClosure task,
base::TimeDelta delay) override;
using MessageLoop::PostDelayedTask;
- TaskId WatchFileDescriptor(const base::Location& from_here,
- int fd,
- WatchMode mode,
- bool persistent,
- const base::Closure& task) override;
- using MessageLoop::WatchFileDescriptor;
bool CancelTask(TaskId task_id) override;
bool RunOnce(bool may_block) override;
// FakeMessageLoop methods:
- // Pretend, for the purpose of the FakeMessageLoop watching for file
- // descriptors, that the file descriptor |fd| readiness to perform the
- // operation described by |mode| is |ready|. Initially, no file descriptor
- // is ready for any operation.
- void SetFileDescriptorReadiness(int fd, WatchMode mode, bool ready);
-
// Return whether there are peding tasks. Useful to check that no
// callbacks were leaked.
bool PendingTasks();
@@ -64,8 +52,7 @@ class BRILLO_EXPORT FakeMessageLoop : public MessageLoop {
private:
struct ScheduledTask {
base::Location location;
- bool persistent;
- base::Closure callback;
+ base::OnceClosure callback;
};
// The sparse list of scheduled pending callbacks.
@@ -79,13 +66,6 @@ class BRILLO_EXPORT FakeMessageLoop : public MessageLoop {
std::vector<std::pair<base::Time, MessageLoop::TaskId>>,
std::greater<std::pair<base::Time, MessageLoop::TaskId>>> fire_order_;
- // The bag of watched (fd, mode) pair associated with the TaskId that's
- // watching them.
- std::multimap<std::pair<int, WatchMode>, MessageLoop::TaskId> fds_watched_;
-
- // The set of (fd, mode) pairs that are faked as ready.
- std::set<std::pair<int, WatchMode>> fds_ready_;
-
base::SimpleTestClock* test_clock_ = nullptr;
base::Time current_time_ = base::Time::FromDoubleT(1246996800.);
diff --git a/brillo/message_loops/fake_message_loop_test.cc b/brillo/message_loops/fake_message_loop_test.cc
index b4b839c..a5d0607 100644
--- a/brillo/message_loops/fake_message_loop_test.cc
+++ b/brillo/message_loops/fake_message_loop_test.cc
@@ -15,7 +15,7 @@
#include <brillo/message_loops/message_loop.h>
-using base::Bind;
+using base::BindOnce;
using base::Time;
using base::TimeDelta;
using std::vector;
@@ -45,17 +45,18 @@ TEST_F(FakeMessageLoopTest, CancelTaskInvalidValuesTest) {
TEST_F(FakeMessageLoopTest, PostDelayedTaskRunsInOrder) {
vector<int> order;
- auto callback = [](std::vector<int>* order, int value) {
- order->push_back(value);
- };
- loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 1),
- TimeDelta::FromSeconds(1));
- loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 4),
- TimeDelta::FromSeconds(4));
- loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 3),
- TimeDelta::FromSeconds(3));
- loop_->PostDelayedTask(Bind(callback, base::Unretained(&order), 2),
- TimeDelta::FromSeconds(2));
+ loop_->PostDelayedTask(
+ BindOnce([](vector<int>* order) { order->push_back(1); }, &order),
+ TimeDelta::FromSeconds(1));
+ loop_->PostDelayedTask(
+ BindOnce([](vector<int>* order) { order->push_back(4); }, &order),
+ TimeDelta::FromSeconds(4));
+ loop_->PostDelayedTask(
+ BindOnce([](vector<int>* order) { order->push_back(3); }, &order),
+ TimeDelta::FromSeconds(3));
+ loop_->PostDelayedTask(
+ BindOnce([](vector<int>* order) { order->push_back(2); }, &order),
+ TimeDelta::FromSeconds(2));
// Run until all the tasks are run.
loop_->Run();
EXPECT_EQ((vector<int>{1, 2, 3, 4}), order);
@@ -84,34 +85,6 @@ TEST_F(FakeMessageLoopTest, PostDelayedTaskAdvancesTheTime) {
EXPECT_EQ(start + TimeDelta::FromSeconds(3), clock_.Now());
}
-TEST_F(FakeMessageLoopTest, WatchFileDescriptorWaits) {
- int fd = 1234;
- // We will simulate this situation. At the beginning, we will watch for a
- // file descriptor that won't trigger for 10s. Then we will pretend it is
- // ready after 10s and expect its callback to run just once.
- int called = 0;
- TaskId task_id = loop_->WatchFileDescriptor(
- FROM_HERE, fd, MessageLoop::kWatchRead, false,
- Bind([](int* called) { (*called)++; }, base::Unretained(&called)));
- EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
-
- EXPECT_NE(MessageLoop::kTaskIdNull,
- loop_->PostDelayedTask(Bind(&FakeMessageLoop::BreakLoop,
- base::Unretained(loop_.get())),
- TimeDelta::FromSeconds(10)));
- EXPECT_NE(MessageLoop::kTaskIdNull,
- loop_->PostDelayedTask(Bind(&FakeMessageLoop::BreakLoop,
- base::Unretained(loop_.get())),
- TimeDelta::FromSeconds(20)));
- loop_->Run();
- EXPECT_EQ(0, called);
-
- loop_->SetFileDescriptorReadiness(fd, MessageLoop::kWatchRead, true);
- loop_->Run();
- EXPECT_EQ(1, called);
- EXPECT_FALSE(loop_->CancelTask(task_id));
-}
-
TEST_F(FakeMessageLoopTest, PendingTasksTest) {
loop_->PostDelayedTask(base::DoNothing(), TimeDelta::FromSeconds(1));
EXPECT_TRUE(loop_->PendingTasks());
diff --git a/brillo/message_loops/message_loop.h b/brillo/message_loops/message_loop.h
index e9f804e..13c4dc2 100644
--- a/brillo/message_loops/message_loop.h
+++ b/brillo/message_loops/message_loop.h
@@ -6,6 +6,7 @@
#define LIBBRILLO_BRILLO_MESSAGE_LOOPS_MESSAGE_LOOP_H_
#include <string>
+#include <utility>
#include <base/callback.h>
#include <base/location.h>
@@ -50,48 +51,20 @@ class BRILLO_EXPORT MessageLoop {
// at a later point.
// This methond can only be called from the same thread running the main loop.
virtual TaskId PostDelayedTask(const base::Location& from_here,
- const base::Closure& task,
+ base::OnceClosure task,
base::TimeDelta delay) = 0;
// Variant without the Location for easier usage.
- TaskId PostDelayedTask(const base::Closure& task, base::TimeDelta delay) {
- return PostDelayedTask(base::Location(), task, delay);
+ TaskId PostDelayedTask(base::OnceClosure task, base::TimeDelta delay) {
+ return PostDelayedTask(base::Location(), std::move(task), delay);
}
// A convenience method to schedule a call with no delay.
// This methond can only be called from the same thread running the main loop.
- TaskId PostTask(const base::Closure& task) {
- return PostDelayedTask(task, base::TimeDelta());
+ TaskId PostTask(base::OnceClosure task) {
+ return PostDelayedTask(std::move(task), base::TimeDelta());
}
- TaskId PostTask(const base::Location& from_here,
- const base::Closure& task) {
- return PostDelayedTask(from_here, task, base::TimeDelta());
- }
-
- // Watch mode flag used to watch for file descriptors.
- enum WatchMode {
- kWatchRead,
- kWatchWrite,
- };
-
- // Watch a file descriptor |fd| for it to be ready to perform the operation
- // passed in |mode| without blocking. When that happens, the |task| closure
- // will be executed. If |persistent| is true, the file descriptor will
- // continue to be watched and |task| will continue to be called until the task
- // is canceled with CancelTask().
- // Returns the TaskId describing this task. In case of error, returns
- // kTaskIdNull.
- virtual TaskId WatchFileDescriptor(const base::Location& from_here,
- int fd,
- WatchMode mode,
- bool persistent,
- const base::Closure& task) = 0;
-
- // Convenience function to call WatchFileDescriptor() without a location.
- TaskId WatchFileDescriptor(int fd,
- WatchMode mode,
- bool persistent,
- const base::Closure& task) {
- return WatchFileDescriptor(base::Location(), fd, mode, persistent, task);
+ TaskId PostTask(const base::Location& from_here, base::OnceClosure task) {
+ return PostDelayedTask(from_here, std::move(task), base::TimeDelta());
}
// Cancel a scheduled task. Returns whether the task was canceled. For
diff --git a/brillo/message_loops/message_loop_test.cc b/brillo/message_loops/message_loop_test.cc
index 7b57015..86c41a6 100644
--- a/brillo/message_loops/message_loop_test.cc
+++ b/brillo/message_loops/message_loop_test.cc
@@ -22,12 +22,13 @@
#include <brillo/message_loops/message_loop_utils.h>
#include <brillo/unittest_utils.h>
-using base::Bind;
+using base::BindOnce;
+using base::BindRepeating;
using base::TimeDelta;
namespace {
-// Convenience functions for passing to base::Bind.
+// Convenience functions for passing to base::Bind{Once,Repeating}.
void SetToTrue(bool* b) {
*b = true;
}
@@ -36,10 +37,6 @@ bool ReturnBool(bool *b) {
return *b;
}
-void Increment(int* i) {
- (*i)++;
-}
-
} // namespace
namespace brillo {
@@ -84,7 +81,8 @@ TYPED_TEST(MessageLoopTest, CancelTaskInvalidValuesTest) {
TYPED_TEST(MessageLoopTest, PostTaskTest) {
bool called = false;
- TaskId task_id = this->loop_->PostTask(FROM_HERE, Bind(&SetToTrue, &called));
+ TaskId task_id =
+ this->loop_->PostTask(FROM_HERE, BindOnce(&SetToTrue, &called));
EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
MessageLoopRunMaxIterations(this->loop_.get(), 100);
EXPECT_TRUE(called);
@@ -93,7 +91,8 @@ TYPED_TEST(MessageLoopTest, PostTaskTest) {
// Tests that we can cancel tasks right after we schedule them.
TYPED_TEST(MessageLoopTest, PostTaskCancelledTest) {
bool called = false;
- TaskId task_id = this->loop_->PostTask(FROM_HERE, Bind(&SetToTrue, &called));
+ TaskId task_id =
+ this->loop_->PostTask(FROM_HERE, BindOnce(&SetToTrue, &called));
EXPECT_TRUE(this->loop_->CancelTask(task_id));
MessageLoopRunMaxIterations(this->loop_.get(), 100);
EXPECT_FALSE(called);
@@ -103,12 +102,12 @@ TYPED_TEST(MessageLoopTest, PostTaskCancelledTest) {
TYPED_TEST(MessageLoopTest, PostDelayedTaskRunsEventuallyTest) {
bool called = false;
- TaskId task_id = this->loop_->PostDelayedTask(
- FROM_HERE, Bind(&SetToTrue, &called), TimeDelta::FromMilliseconds(50));
+ TaskId task_id =
+ this->loop_->PostDelayedTask(FROM_HERE, BindOnce(&SetToTrue, &called),
+ TimeDelta::FromMilliseconds(50));
EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
- MessageLoopRunUntil(this->loop_.get(),
- TimeDelta::FromSeconds(10),
- Bind(&ReturnBool, &called));
+ MessageLoopRunUntil(this->loop_.get(), TimeDelta::FromSeconds(10),
+ BindRepeating(&ReturnBool, &called));
// Check that the main loop finished before the 10 seconds timeout, so it
// finished due to the callback being called and not due to the timeout.
EXPECT_TRUE(called);
@@ -122,251 +121,19 @@ TYPED_TEST(MessageLoopTest, PostDelayedTaskWithoutLocation) {
EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
}
-TYPED_TEST(MessageLoopTest, WatchForInvalidFD) {
- bool called = false;
- EXPECT_EQ(MessageLoop::kTaskIdNull, this->loop_->WatchFileDescriptor(
- FROM_HERE, -1, MessageLoop::kWatchRead, true,
- Bind(&SetToTrue, &called)));
- EXPECT_EQ(MessageLoop::kTaskIdNull, this->loop_->WatchFileDescriptor(
- FROM_HERE, -1, MessageLoop::kWatchWrite, true,
- Bind(&SetToTrue, &called)));
- EXPECT_EQ(0, MessageLoopRunMaxIterations(this->loop_.get(), 100));
- EXPECT_FALSE(called);
-}
-
-TYPED_TEST(MessageLoopTest, CancelWatchedFileDescriptor) {
- ScopedPipe pipe;
- bool called = false;
- TaskId task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
- Bind(&SetToTrue, &called));
- EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
- // The reader end is blocked because we didn't write anything to the writer
- // end.
- EXPECT_EQ(0, MessageLoopRunMaxIterations(this->loop_.get(), 100));
- EXPECT_FALSE(called);
- EXPECT_TRUE(this->loop_->CancelTask(task_id));
-}
-
-// When you watch a file descriptor for reading, the guaranties are that a
-// blocking call to read() on that file descriptor will not block. This should
-// include the case when the other end of a pipe is closed or the file is empty.
-TYPED_TEST(MessageLoopTest, WatchFileDescriptorTriggersWhenPipeClosed) {
- ScopedPipe pipe;
- bool called = false;
- EXPECT_EQ(0, HANDLE_EINTR(close(pipe.writer)));
- pipe.writer = -1;
- TaskId task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
- Bind(&SetToTrue, &called));
- EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
- // The reader end is not blocked because we closed the writer end so a read on
- // the reader end would return 0 bytes read.
- EXPECT_NE(0, MessageLoopRunMaxIterations(this->loop_.get(), 10));
- EXPECT_TRUE(called);
- EXPECT_TRUE(this->loop_->CancelTask(task_id));
-}
-
-// When a WatchFileDescriptor task is scheduled with |persistent| = true, we
-// should keep getting a call whenever the file descriptor is ready.
-TYPED_TEST(MessageLoopTest, WatchFileDescriptorPersistently) {
- ScopedPipe pipe;
- EXPECT_EQ(1, HANDLE_EINTR(write(pipe.writer, "a", 1)));
-
- int called = 0;
- TaskId task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipe.reader, MessageLoop::kWatchRead, true,
- Bind(&Increment, &called));
- EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
- // We let the main loop run for 20 iterations to give it enough iterations to
- // verify that our callback was called more than one. We only check that our
- // callback is called more than once.
- EXPECT_EQ(20, MessageLoopRunMaxIterations(this->loop_.get(), 20));
- EXPECT_LT(1, called);
- EXPECT_TRUE(this->loop_->CancelTask(task_id));
-}
-
-TYPED_TEST(MessageLoopTest, WatchFileDescriptorNonPersistent) {
- ScopedPipe pipe;
- EXPECT_EQ(1, HANDLE_EINTR(write(pipe.writer, "a", 1)));
-
- int called = 0;
- TaskId task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipe.reader, MessageLoop::kWatchRead, false,
- Bind(&Increment, &called));
- EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
- // We let the main loop run for 20 iterations but we just expect it to run
- // at least once. The callback should be called exactly once since we
- // scheduled it non-persistently. After it ran, we shouldn't be able to cancel
- // this task.
- EXPECT_LT(0, MessageLoopRunMaxIterations(this->loop_.get(), 20));
- EXPECT_EQ(1, called);
- EXPECT_FALSE(this->loop_->CancelTask(task_id));
-}
-
-TYPED_TEST(MessageLoopTest, WatchFileDescriptorForReadAndWriteSimultaneously) {
- ScopedSocketPair socks;
- EXPECT_EQ(1, HANDLE_EINTR(write(socks.right, "a", 1)));
- // socks.left should be able to read this "a" and should also be able to write
- // without blocking since the kernel has some buffering for it.
-
- TaskId read_task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, socks.left, MessageLoop::kWatchRead, true,
- Bind([] (MessageLoop* loop, TaskId* read_task_id) {
- EXPECT_TRUE(loop->CancelTask(*read_task_id))
- << "task_id" << *read_task_id;
- }, this->loop_.get(), &read_task_id));
- EXPECT_NE(MessageLoop::kTaskIdNull, read_task_id);
-
- TaskId write_task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, socks.left, MessageLoop::kWatchWrite, true,
- Bind([] (MessageLoop* loop, TaskId* write_task_id) {
- EXPECT_TRUE(loop->CancelTask(*write_task_id));
- }, this->loop_.get(), &write_task_id));
- EXPECT_NE(MessageLoop::kTaskIdNull, write_task_id);
-
- EXPECT_LT(0, MessageLoopRunMaxIterations(this->loop_.get(), 20));
-
- EXPECT_FALSE(this->loop_->CancelTask(read_task_id));
- EXPECT_FALSE(this->loop_->CancelTask(write_task_id));
-}
-
// Test that we can cancel the task we are running, and should just fail.
TYPED_TEST(MessageLoopTest, DeleteTaskFromSelf) {
bool cancel_result = true; // We would expect this to be false.
TaskId task_id;
task_id = this->loop_->PostTask(
FROM_HERE,
- Bind([](bool* cancel_result, MessageLoop* loop, TaskId* task_id) {
- *cancel_result = loop->CancelTask(*task_id);
- }, &cancel_result, this->loop_.get(), &task_id));
+ BindOnce(
+ [](bool* cancel_result, MessageLoop* loop, TaskId* task_id) {
+ *cancel_result = loop->CancelTask(*task_id);
+ },
+ &cancel_result, this->loop_.get(), &task_id));
EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
EXPECT_FALSE(cancel_result);
}
-// Test that we can cancel a non-persistent file descriptor watching callback,
-// which should fail.
-TYPED_TEST(MessageLoopTest, DeleteNonPersistenIOTaskFromSelf) {
- ScopedPipe pipe;
- TaskId task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipe.writer, MessageLoop::kWatchWrite, false /* persistent */,
- Bind([](MessageLoop* loop, TaskId* task_id) {
- EXPECT_FALSE(loop->CancelTask(*task_id));
- *task_id = MessageLoop::kTaskIdNull;
- }, this->loop_.get(), &task_id));
- EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
- EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
- EXPECT_EQ(MessageLoop::kTaskIdNull, task_id);
-}
-
-// Test that we can cancel a persistent file descriptor watching callback from
-// the same callback.
-TYPED_TEST(MessageLoopTest, DeletePersistenIOTaskFromSelf) {
- ScopedPipe pipe;
- TaskId task_id = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipe.writer, MessageLoop::kWatchWrite, true /* persistent */,
- Bind([](MessageLoop* loop, TaskId* task_id) {
- EXPECT_TRUE(loop->CancelTask(*task_id));
- *task_id = MessageLoop::kTaskIdNull;
- }, this->loop_.get(), &task_id));
- EXPECT_NE(MessageLoop::kTaskIdNull, task_id);
- EXPECT_EQ(1, MessageLoopRunMaxIterations(this->loop_.get(), 100));
- EXPECT_EQ(MessageLoop::kTaskIdNull, task_id);
-}
-
-// Test that we can cancel several persistent file descriptor watching callbacks
-// from a scheduled callback. In the BaseMessageLoop implementation, this code
-// will cause us to cancel an IOTask that has a pending delayed task, but
-// otherwise is a valid test case on all implementations.
-TYPED_TEST(MessageLoopTest, DeleteAllPersistenIOTaskFromSelf) {
- const int kNumTasks = 5;
- ScopedPipe pipes[kNumTasks];
- TaskId task_ids[kNumTasks];
-
- for (int i = 0; i < kNumTasks; ++i) {
- task_ids[i] = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipes[i].writer, MessageLoop::kWatchWrite,
- true /* persistent */,
- Bind([] (MessageLoop* loop, TaskId* task_ids) {
- for (int j = 0; j < kNumTasks; ++j) {
- // Once we cancel all the tasks, none should run, so this code runs
- // only once from one callback.
- EXPECT_TRUE(loop->CancelTask(task_ids[j]));
- task_ids[j] = MessageLoop::kTaskIdNull;
- }
- }, this->loop_.get(), task_ids));
- }
- MessageLoopRunMaxIterations(this->loop_.get(), 100);
- for (int i = 0; i < kNumTasks; ++i) {
- EXPECT_EQ(MessageLoop::kTaskIdNull, task_ids[i]);
- }
-}
-
-// Test that if there are several tasks watching for file descriptors to be
-// available or simply waiting in the message loop are fairly scheduled to run.
-// In other words, this test ensures that having a file descriptor always
-// available doesn't prevent other file descriptors watching tasks or delayed
-// tasks to be dispatched, causing starvation.
-TYPED_TEST(MessageLoopTest, AllTasksAreEqual) {
- int total_calls = 0;
-
- // First, schedule a repeating timeout callback to run from the main loop.
- int timeout_called = 0;
- base::Closure timeout_callback;
- MessageLoop::TaskId timeout_task;
- timeout_callback = base::Bind(
- [](MessageLoop* loop, int* timeout_called, int* total_calls,
- base::Closure* timeout_callback, MessageLoop::TaskId* timeout_task) {
- (*timeout_called)++;
- (*total_calls)++;
- *timeout_task = loop->PostTask(FROM_HERE, *timeout_callback);
- if (*total_calls > 100)
- loop->BreakLoop();
- },
- this->loop_.get(), &timeout_called, &total_calls, &timeout_callback,
- &timeout_task);
- timeout_task = this->loop_->PostTask(FROM_HERE, timeout_callback);
-
- // Second, schedule several file descriptor watchers.
- const int kNumTasks = 3;
- ScopedPipe pipes[kNumTasks];
- MessageLoop::TaskId tasks[kNumTasks];
-
- int reads[kNumTasks] = {};
- base::Callback<void(int)> fd_callback = base::Bind(
- [](MessageLoop* loop, ScopedPipe* pipes, int* reads,
- int* total_calls, int i) {
- reads[i]++;
- (*total_calls)++;
- char c;
- EXPECT_EQ(1, HANDLE_EINTR(read(pipes[i].reader, &c, 1)));
- if (*total_calls > 100)
- loop->BreakLoop();
- }, this->loop_.get(), pipes, reads, &total_calls);
-
- for (int i = 0; i < kNumTasks; ++i) {
- tasks[i] = this->loop_->WatchFileDescriptor(
- FROM_HERE, pipes[i].reader, MessageLoop::kWatchRead,
- true /* persistent */,
- Bind(fd_callback, i));
- // Make enough bytes available on each file descriptor. This should not
- // block because we set the size of the file descriptor buffer when
- // creating it.
- std::vector<char> blob(1000, 'a');
- EXPECT_EQ(blob.size(),
- HANDLE_EINTR(write(pipes[i].writer, blob.data(), blob.size())));
- }
- this->loop_->Run();
- EXPECT_GT(total_calls, 100);
- // We run the loop up 100 times and expect each callback to run at least 10
- // times. A good scheduler should balance these callbacks.
- EXPECT_GE(timeout_called, 10);
- EXPECT_TRUE(this->loop_->CancelTask(timeout_task));
- for (int i = 0; i < kNumTasks; ++i) {
- EXPECT_GE(reads[i], 10) << "Reading from pipes[" << i << "], fd "
- << pipes[i].reader;
- EXPECT_TRUE(this->loop_->CancelTask(tasks[i]));
- }
-}
-
} // namespace brillo
diff --git a/brillo/message_loops/message_loop_utils.cc b/brillo/message_loops/message_loop_utils.cc
index c16f268..0f3214b 100644
--- a/brillo/message_loops/message_loop_utils.cc
+++ b/brillo/message_loops/message_loop_utils.cc
@@ -9,15 +9,14 @@
namespace brillo {
-void MessageLoopRunUntil(
- MessageLoop* loop,
- base::TimeDelta timeout,
- base::Callback<bool()> terminate) {
+void MessageLoopRunUntil(MessageLoop* loop,
+ base::TimeDelta timeout,
+ base::RepeatingCallback<bool()> terminate) {
bool timeout_called = false;
MessageLoop::TaskId task_id = loop->PostDelayedTask(
FROM_HERE,
- base::Bind([](bool* timeout_called) { *timeout_called = true; },
- base::Unretained(&timeout_called)),
+ base::BindOnce([](bool* timeout_called) { *timeout_called = true; },
+ &timeout_called),
timeout);
while (!timeout_called && (terminate.is_null() || !terminate.Run()))
loop->RunOnce(true);
diff --git a/brillo/message_loops/message_loop_utils.h b/brillo/message_loops/message_loop_utils.h
index d49ebdf..7384ddb 100644
--- a/brillo/message_loops/message_loop_utils.h
+++ b/brillo/message_loops/message_loop_utils.h
@@ -18,7 +18,7 @@ namespace brillo {
BRILLO_EXPORT void MessageLoopRunUntil(
MessageLoop* loop,
base::TimeDelta timeout,
- base::Callback<bool()> terminate);
+ base::RepeatingCallback<bool()> terminate);
// Run the MessageLoop |loop| for up to |iterations| times without blocking.
// Return the number of tasks run.
diff --git a/brillo/message_loops/mock_message_loop.h b/brillo/message_loops/mock_message_loop.h
index c84e585..357ec24 100644
--- a/brillo/message_loops/mock_message_loop.h
+++ b/brillo/message_loops/mock_message_loop.h
@@ -37,17 +37,9 @@ class BRILLO_EXPORT MockMessageLoop : public MessageLoop {
&fake_loop_,
static_cast<TaskId(FakeMessageLoop::*)(
const base::Location&,
- const base::Closure&,
+ base::OnceClosure,
base::TimeDelta)>(
&FakeMessageLoop::PostDelayedTask)));
- ON_CALL(*this, WatchFileDescriptor(
- ::testing::_, ::testing::_, ::testing::_, ::testing::_, ::testing::_))
- .WillByDefault(::testing::Invoke(
- &fake_loop_,
- static_cast<TaskId(FakeMessageLoop::*)(
- const base::Location&, int, WatchMode, bool,
- const base::Closure&)>(
- &FakeMessageLoop::WatchFileDescriptor)));
ON_CALL(*this, CancelTask(::testing::_))
.WillByDefault(::testing::Invoke(&fake_loop_,
&FakeMessageLoop::CancelTask));
@@ -59,15 +51,9 @@ class BRILLO_EXPORT MockMessageLoop : public MessageLoop {
MOCK_METHOD(TaskId,
PostDelayedTask,
- (const base::Location&, const base::Closure&, base::TimeDelta),
+ (const base::Location&, base::OnceClosure, base::TimeDelta),
(override));
using MessageLoop::PostDelayedTask;
- MOCK_METHOD(
- TaskId,
- WatchFileDescriptor,
- (const base::Location&, int, WatchMode, bool, const base::Closure&),
- (override));
- using MessageLoop::WatchFileDescriptor;
MOCK_METHOD(bool, CancelTask, (TaskId), (override));
MOCK_METHOD(bool, RunOnce, (bool), (override));
diff --git a/brillo/minijail/minijail.cc b/brillo/minijail/minijail.cc
index a08233d..9f88585 100644
--- a/brillo/minijail/minijail.cc
+++ b/brillo/minijail/minijail.cc
@@ -121,6 +121,23 @@ bool Minijail::RunPipes(struct minijail* jail,
#endif // __ANDROID__
}
+bool Minijail::RunEnvPipes(struct minijail* jail,
+ vector<char*> args,
+ vector<char*> env,
+ pid_t* pid,
+ int* stdin,
+ int* stdout,
+ int* stderr) {
+#if defined(__ANDROID__)
+ return minijail_run_env_pid_pipes_no_preload(jail, args[0], args.data(),
+ env.data(), pid, stdin, stdout,
+ stderr) == 0;
+#else
+ return minijail_run_env_pid_pipes(jail, args[0], args.data(), env.data(), pid,
+ stdin, stdout, stderr) == 0;
+#endif // __ANDROID__
+}
+
bool Minijail::RunAndDestroy(struct minijail* jail,
vector<char*> args,
pid_t* pid) {
@@ -157,4 +174,16 @@ bool Minijail::RunPipesAndDestroy(struct minijail* jail,
return res;
}
+bool Minijail::RunEnvPipesAndDestroy(struct minijail* jail,
+ vector<char*> args,
+ vector<char*> env,
+ pid_t* pid,
+ int* stdin,
+ int* stdout,
+ int* stderr) {
+ bool res = RunEnvPipes(jail, args, env, pid, stdin, stdout, stderr);
+ Destroy(jail);
+ return res;
+}
+
} // namespace brillo
diff --git a/brillo/minijail/minijail.h b/brillo/minijail/minijail.h
index c71211d..6cdc7ad 100644
--- a/brillo/minijail/minijail.h
+++ b/brillo/minijail/minijail.h
@@ -89,6 +89,14 @@ class BRILLO_EXPORT Minijail {
int* stdout,
int* stderr);
+ // minijail_run_env_pid_pipes
+ virtual bool RunEnvPipes(struct minijail* jail,
+ std::vector<char*> args,
+ std::vector<char*> env,
+ pid_t* pid,
+ int* stdin,
+ int* stdout,
+ int* stderr);
// Run() and Destroy()
virtual bool RunAndDestroy(struct minijail* jail,
std::vector<char*> args,
@@ -113,6 +121,15 @@ class BRILLO_EXPORT Minijail {
int* stdout,
int* stderr);
+ // RunEnvPipes() and Destroy()
+ virtual bool RunEnvPipesAndDestroy(struct minijail* jail,
+ std::vector<char*> args,
+ std::vector<char*> env,
+ pid_t* pid,
+ int* stdin,
+ int* stdout,
+ int* stderr);
+
protected:
Minijail();
diff --git a/brillo/minijail/mock_minijail.h b/brillo/minijail/mock_minijail.h
index 6c95405..21e7ad7 100644
--- a/brillo/minijail/mock_minijail.h
+++ b/brillo/minijail/mock_minijail.h
@@ -44,6 +44,20 @@ class MockMinijail : public brillo::Minijail {
(struct minijail*, std::vector<char*>, int*),
(override));
MOCK_METHOD(bool,
+ RunPipes,
+ (struct minijail*, std::vector<char*>, pid_t*, int*, int*, int*),
+ (override));
+ MOCK_METHOD(bool,
+ RunEnvPipes,
+ (struct minijail*,
+ std::vector<char*>,
+ std::vector<char*>,
+ pid_t*,
+ int*,
+ int*,
+ int*),
+ (override));
+ MOCK_METHOD(bool,
RunAndDestroy,
(struct minijail*, std::vector<char*>, pid_t*),
(override));
@@ -59,6 +73,16 @@ class MockMinijail : public brillo::Minijail {
RunPipesAndDestroy,
(struct minijail*, std::vector<char*>, pid_t*, int*, int*, int*),
(override));
+ MOCK_METHOD(bool,
+ RunEnvPipesAndDestroy,
+ (struct minijail*,
+ std::vector<char*>,
+ std::vector<char*>,
+ pid_t*,
+ int*,
+ int*,
+ int*),
+ (override));
private:
DISALLOW_COPY_AND_ASSIGN(MockMinijail);
diff --git a/brillo/namespaces/OWNERS b/brillo/namespaces/OWNERS
new file mode 100644
index 0000000..e96f211
--- /dev/null
+++ b/brillo/namespaces/OWNERS
@@ -0,0 +1,2 @@
+betuls@chromium.org
+jorgelo@chromium.org
diff --git a/brillo/namespaces/mock_platform.h b/brillo/namespaces/mock_platform.h
new file mode 100644
index 0000000..1b96b46
--- /dev/null
+++ b/brillo/namespaces/mock_platform.h
@@ -0,0 +1,37 @@
+// Copyright 2020 The Chromium OS 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 LIBBRILLO_BRILLO_NAMESPACES_MOCK_PLATFORM_H_
+#define LIBBRILLO_BRILLO_NAMESPACES_MOCK_PLATFORM_H_
+
+#include "brillo/namespaces/platform.h"
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <gmock/gmock.h>
+
+namespace brillo {
+
+class MockPlatform : public Platform {
+ public:
+ MockPlatform() {}
+ virtual ~MockPlatform() {}
+
+ MOCK_METHOD(bool, Unmount, (const base::FilePath&, bool, bool*), (override));
+ MOCK_METHOD(pid_t, Fork, (), (override));
+ MOCK_METHOD(pid_t, Waitpid, (pid_t, int*), (override));
+ MOCK_METHOD(int,
+ Mount,
+ (const std::string&,
+ const std::string&,
+ const std::string&,
+ uint64_t,
+ const void*),
+ (override));
+};
+
+} // namespace brillo
+
+#endif // LIBBRILLO_BRILLO_NAMESPACES_MOCK_PLATFORM_H_
diff --git a/brillo/namespaces/mount_namespace.cc b/brillo/namespaces/mount_namespace.cc
new file mode 100644
index 0000000..1944983
--- /dev/null
+++ b/brillo/namespaces/mount_namespace.cc
@@ -0,0 +1,114 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Contains the implementation of class MountNamespace for libbrillo.
+
+#include "brillo/namespaces/mount_namespace.h"
+
+#include <sched.h>
+#include <sys/mount.h>
+#include <sys/types.h>
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/files/file_util.h>
+#include <base/logging.h>
+#include <base/strings/stringprintf.h>
+#include <brillo/namespaces/platform.h>
+
+namespace brillo {
+MountNamespace::MountNamespace(const base::FilePath& ns_path,
+ Platform* platform)
+ : ns_path_(ns_path), platform_(platform), exists_(false) {}
+
+MountNamespace::~MountNamespace() {
+ if (exists_)
+ Destroy();
+}
+
+bool MountNamespace::Create() {
+ if (platform_->FileSystemIsNsfs(ns_path_)) {
+ LOG(ERROR) << "Mount namespace at " << ns_path_.value()
+ << " already exists.";
+ return false;
+ }
+ int fd_mounted[2];
+ int fd_unshared[2];
+ char byte = '\0';
+ if (pipe(fd_mounted) != 0) {
+ PLOG(ERROR) << "Cannot create mount signalling pipe";
+ return false;
+ }
+ if (pipe(fd_unshared) != 0) {
+ PLOG(ERROR) << "Cannot create unshare signalling pipe";
+ return false;
+ }
+ pid_t pid = platform_->Fork();
+ if (pid < 0) {
+ PLOG(ERROR) << "Fork failed";
+ } else if (pid == 0) {
+ // Child.
+ close(fd_mounted[1]);
+ close(fd_unshared[0]);
+ if (unshare(CLONE_NEWNS) != 0) {
+ PLOG(ERROR) << "unshare(CLONE_NEWNS) failed";
+ exit(1);
+ }
+ base::WriteFileDescriptor(fd_unshared[1], &byte, 1);
+ base::ReadFromFD(fd_mounted[0], &byte, 1);
+ exit(0);
+ } else {
+ // Parent.
+ close(fd_mounted[0]);
+ close(fd_unshared[1]);
+ std::string proc_ns_path = base::StringPrintf("/proc/%d/ns/mnt", pid);
+ bool mount_success = true;
+ base::ReadFromFD(fd_unshared[0], &byte, 1);
+ if (platform_->Mount(proc_ns_path, ns_path_.value(), "", MS_BIND) != 0) {
+ PLOG(ERROR) << "Mount(" << proc_ns_path << ", " << ns_path_.value()
+ << ", MS_BIND) failed";
+ mount_success = false;
+ }
+ base::WriteFileDescriptor(fd_mounted[1], &byte, 1);
+
+ int status;
+ if (platform_->Waitpid(pid, &status) < 0) {
+ PLOG(ERROR) << "waitpid(" << pid << ") failed";
+ return false;
+ }
+ if (!WIFEXITED(status)) {
+ LOG(ERROR) << "Child process did not exit normally.";
+ } else if (WEXITSTATUS(status) != 0) {
+ LOG(ERROR) << "Child process failed.";
+ } else {
+ exists_ = mount_success;
+ }
+ }
+ return exists_;
+}
+
+bool MountNamespace::Destroy() {
+ if (!exists_) {
+ LOG(ERROR) << "Mount namespace at " << ns_path_.value()
+ << "does not exist, cannot destroy";
+ return false;
+ }
+ bool was_busy;
+ if (!platform_->Unmount(ns_path_, false /*lazy*/, &was_busy)) {
+ PLOG(ERROR) << "Failed to unmount " << ns_path_.value();
+ if (was_busy) {
+ LOG(ERROR) << ns_path_.value().c_str() << " was busy";
+ }
+ // If Unmount() fails, keep the object valid by keeping |exists_|
+ // set to true.
+ return false;
+ } else {
+ VLOG(1) << "Unmounted namespace at " << ns_path_.value();
+ }
+ exists_ = false;
+ return true;
+}
+
+} // namespace brillo
diff --git a/brillo/namespaces/mount_namespace.h b/brillo/namespaces/mount_namespace.h
new file mode 100644
index 0000000..bfadff0
--- /dev/null
+++ b/brillo/namespaces/mount_namespace.h
@@ -0,0 +1,70 @@
+// Copyright 2020 The Chromium OS 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 LIBBRILLO_BRILLO_NAMESPACES_MOUNT_NAMESPACE_H_
+#define LIBBRILLO_BRILLO_NAMESPACES_MOUNT_NAMESPACE_H_
+
+#include "brillo/namespaces/platform.h"
+
+#include <base/files/file_path.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+class BRILLO_EXPORT MountNamespaceInterface {
+ // An interface declaring the basic functionality of a mount namespace bound
+ // to a specific path. This basic functionality consists of reporting the
+ // namespace path.
+ public:
+ virtual ~MountNamespaceInterface() = default;
+
+ virtual const base::FilePath& path() const = 0;
+};
+
+class BRILLO_EXPORT UnownedMountNamespace : public MountNamespaceInterface {
+ // A class to store and retrieve the path of a persistent namespace. This
+ // class doesn't create nor destroy the namespace.
+ public:
+ explicit UnownedMountNamespace(const base::FilePath& ns_path)
+ : ns_path_(ns_path) {}
+
+ ~UnownedMountNamespace() override;
+
+ const base::FilePath& path() const override { return ns_path_; }
+
+ private:
+ base::FilePath ns_path_;
+
+ DISALLOW_COPY_AND_ASSIGN(UnownedMountNamespace);
+};
+
+class BRILLO_EXPORT MountNamespace : public MountNamespaceInterface {
+ // A class to create a persistent mount namespace bound to a specific path.
+ // A new mount namespace is unshared from the mount namespace of the calling
+ // process when Create() is called; the namespace of the calling process
+ // remains unchanged. Recurring creation on a path is not allowed.
+ //
+ // Given that we cannot ensure that creation always succeeds this class is not
+ // fully RAII, but once the namespace is created (with Create()), it will be
+ // destroyed when the object goes out of scope.
+ public:
+ MountNamespace(const base::FilePath& ns_path, Platform* platform);
+ ~MountNamespace() override;
+
+ bool Create();
+ bool Destroy();
+ const base::FilePath& path() const override { return ns_path_; }
+
+ private:
+ base::FilePath ns_path_;
+ Platform* platform_;
+ bool exists_;
+
+ DISALLOW_COPY_AND_ASSIGN(MountNamespace);
+};
+
+} // namespace brillo
+
+#endif // LIBBRILLO_BRILLO_NAMESPACES_MOUNT_NAMESPACE_H_
diff --git a/brillo/namespaces/mount_namespace_test.cc b/brillo/namespaces/mount_namespace_test.cc
new file mode 100644
index 0000000..1bfa038
--- /dev/null
+++ b/brillo/namespaces/mount_namespace_test.cc
@@ -0,0 +1,92 @@
+// Copyright 2020 The Chromium OS 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 "brillo/namespaces/mock_platform.h"
+#include "brillo/namespaces/mount_namespace.h"
+#include "brillo/namespaces/platform.h"
+
+#include <unistd.h>
+
+#include <memory>
+
+#include <base/files/file_path.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+
+namespace brillo {
+
+class MountNamespaceTest : public ::testing::Test {
+ public:
+ MountNamespaceTest() {}
+ ~MountNamespaceTest() {}
+ void SetUp() {}
+
+ void TearDown() {}
+
+ protected:
+ NiceMock<MockPlatform> platform_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MountNamespaceTest);
+};
+
+TEST_F(MountNamespaceTest, CreateNamespace) {
+ std::unique_ptr<MountNamespace> ns =
+ std::make_unique<MountNamespace>(base::FilePath(), &platform_);
+ EXPECT_CALL(platform_, Fork()).WillOnce(Return(1));
+ EXPECT_CALL(platform_, Mount(_, _, _, _, _)).WillOnce(Return(0));
+ EXPECT_CALL(platform_, Waitpid(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(0x00000000), Return(0)));
+ EXPECT_TRUE(ns->Create());
+ EXPECT_CALL(platform_, Unmount(ns->path(), _, _)).WillOnce(Return(true));
+}
+
+TEST_F(MountNamespaceTest, CreateNamespaceFailedOnWaitpid) {
+ std::unique_ptr<MountNamespace> ns =
+ std::make_unique<MountNamespace>(base::FilePath(), &platform_);
+ EXPECT_CALL(platform_, Fork()).WillOnce(Return(1));
+ EXPECT_CALL(platform_, Mount(_, _, _, _, _)).WillOnce(Return(0));
+ EXPECT_CALL(platform_, Waitpid(_, _)).WillOnce(Return(-1));
+ EXPECT_FALSE(ns->Create());
+}
+
+TEST_F(MountNamespaceTest, CreateNamespaceFailedOnMount) {
+ std::unique_ptr<MountNamespace> ns =
+ std::make_unique<MountNamespace>(base::FilePath(), &platform_);
+ EXPECT_CALL(platform_, Fork()).WillOnce(Return(1));
+ EXPECT_CALL(platform_, Mount(_, _, _, _, _)).WillOnce(Return(-1));
+ EXPECT_FALSE(ns->Create());
+}
+
+TEST_F(MountNamespaceTest, CreateNamespaceFailedOnStatus) {
+ std::unique_ptr<MountNamespace> ns =
+ std::make_unique<MountNamespace>(base::FilePath(), &platform_);
+ EXPECT_CALL(platform_, Fork()).WillOnce(Return(1));
+ EXPECT_CALL(platform_, Mount(_, _, _, _, _)).WillOnce(Return(0));
+ EXPECT_CALL(platform_, Waitpid(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(0xFFFFFFFF), Return(0)));
+ EXPECT_FALSE(ns->Create());
+}
+
+TEST_F(MountNamespaceTest, DestroyAfterUnmountFailsAndUnmountSucceeds) {
+ std::unique_ptr<MountNamespace> ns =
+ std::make_unique<MountNamespace>(base::FilePath(), &platform_);
+ EXPECT_CALL(platform_, Fork()).WillOnce(Return(1));
+ EXPECT_CALL(platform_, Mount(_, _, _, _, _)).WillOnce(Return(0));
+ EXPECT_CALL(platform_, Waitpid(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(0x00000000), Return(0)));
+ EXPECT_TRUE(ns->Create());
+ EXPECT_CALL(platform_, Unmount(ns->path(), _, _)).WillOnce(Return(false));
+ EXPECT_FALSE(ns->Destroy());
+ EXPECT_CALL(platform_, Unmount(ns->path(), _, _)).WillOnce(Return(true));
+ EXPECT_TRUE(ns->Destroy());
+}
+
+} // namespace brillo
diff --git a/brillo/namespaces/platform.cc b/brillo/namespaces/platform.cc
new file mode 100644
index 0000000..5fe9140
--- /dev/null
+++ b/brillo/namespaces/platform.cc
@@ -0,0 +1,75 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Contains the implementation of class Platform for libbrillo.
+
+#include "brillo/namespaces/platform.h"
+
+#include <errno.h>
+#include <linux/magic.h>
+#include <stdio.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/vfs.h>
+#include <sys/wait.h>
+
+#include <memory>
+
+#include <base/files/file_path.h>
+
+using base::FilePath;
+
+namespace brillo {
+
+Platform::Platform() {}
+
+Platform::~Platform() {}
+
+bool Platform::FileSystemIsNsfs(const FilePath& ns_path) {
+ struct statfs buff;
+ if (statfs(ns_path.value().c_str(), &buff) < 0) {
+ PLOG(ERROR) << "Statfs() error for " << ns_path.value();
+ return false;
+ }
+ if ((uint64_t)buff.f_type == NSFS_MAGIC) {
+ return true;
+ }
+ return false;
+}
+
+bool Platform::Unmount(const FilePath& path, bool lazy, bool* was_busy) {
+ int flags = 0;
+ if (lazy) {
+ flags = MNT_DETACH;
+ }
+ if (umount2(path.value().c_str(), flags) != 0) {
+ if (was_busy) {
+ *was_busy = (errno == EBUSY);
+ }
+ return false;
+ }
+ if (was_busy) {
+ *was_busy = false;
+ }
+ return true;
+}
+
+int Platform::Mount(const std::string& source,
+ const std::string& target,
+ const std::string& fs_type,
+ uint64_t mount_flags,
+ const void* data) {
+ return mount(source.c_str(), target.c_str(), fs_type.c_str(), mount_flags,
+ data);
+}
+
+pid_t Platform::Fork() {
+ return fork();
+}
+
+pid_t Platform::Waitpid(pid_t pid, int* status) {
+ return waitpid(pid, status, 0);
+}
+
+} // namespace brillo
diff --git a/brillo/namespaces/platform.h b/brillo/namespaces/platform.h
new file mode 100644
index 0000000..6ef6a73
--- /dev/null
+++ b/brillo/namespaces/platform.h
@@ -0,0 +1,71 @@
+// Copyright 2020 The Chromium OS 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 LIBBRILLO_BRILLO_NAMESPACES_PLATFORM_H_
+#define LIBBRILLO_BRILLO_NAMESPACES_PLATFORM_H_
+
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/macros.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+// Platform specific routines abstraction layer.
+// Also helps us to be able to mock them in tests.
+class BRILLO_EXPORT Platform {
+ public:
+ Platform();
+
+ virtual ~Platform();
+ // Calls the platform fork() function and returns the pid returned
+ // by fork().
+ virtual pid_t Fork();
+
+ // Calls the platform unmount.
+ //
+ // Parameters
+ // path - The path to unmount
+ // lazy - Whether to call a lazy unmount
+ // was_busy (OUT) - Set to true on return if the mount point was busy
+ virtual bool Unmount(const base::FilePath& path, bool lazy, bool* was_busy);
+
+ // Calls the platform mount.
+ //
+ // Parameters
+ // source - The path to mount from
+ // target - The path to mount to
+ // fs_type - File system type of the mount
+ // mount_flags - Flags spesifying the type of the mount operation
+ // data - Mount options
+ virtual int Mount(const std::string& source,
+ const std::string& target,
+ const std::string& fs_type,
+ uint64_t mount_flags,
+ const void* = nullptr);
+
+ // Checks the file system type of the |path| and returns true if the
+ // filesystem type is nsfs.
+ //
+ // Parameters
+ // path - The path to check the file system type
+ virtual bool FileSystemIsNsfs(const base::FilePath& path);
+
+ // Calls the platform waitpid() function and returns the value returned by
+ // waitpid().
+ //
+ // Parameters
+ // pid - The child pid to be waited on
+ // status (OUT)- Termination status of a child process.
+ virtual pid_t Waitpid(pid_t pid, int* status);
+
+ DISALLOW_COPY_AND_ASSIGN(Platform);
+};
+
+} // namespace brillo
+
+#endif // LIBBRILLO_BRILLO_NAMESPACES_PLATFORM_H_
diff --git a/brillo/scoped_mount_namespace.cc b/brillo/scoped_mount_namespace.cc
index 0f35e82..09f3c75 100644
--- a/brillo/scoped_mount_namespace.cc
+++ b/brillo/scoped_mount_namespace.cc
@@ -38,7 +38,7 @@ std::unique_ptr<ScopedMountNamespace> ScopedMountNamespace::CreateForPid(
// static
std::unique_ptr<ScopedMountNamespace> ScopedMountNamespace::CreateFromPath(
- base::FilePath ns_path) {
+ const base::FilePath& ns_path) {
base::ScopedFD original_mount_namespace_fd(
HANDLE_EINTR(open(kCurrentMountNamespacePath, O_RDONLY)));
if (!original_mount_namespace_fd.is_valid()) {
diff --git a/brillo/scoped_mount_namespace.h b/brillo/scoped_mount_namespace.h
index f360221..e029d78 100644
--- a/brillo/scoped_mount_namespace.h
+++ b/brillo/scoped_mount_namespace.h
@@ -28,7 +28,7 @@ class BRILLO_EXPORT ScopedMountNamespace {
// Enters the mount namespace identified by |path| and returns a unique_ptr
// that restores the original mount namespace when it goes out of scope.
static std::unique_ptr<ScopedMountNamespace> CreateFromPath(
- base::FilePath ns_path);
+ const base::FilePath& ns_path);
explicit ScopedMountNamespace(base::ScopedFD mount_namespace_fd);
~ScopedMountNamespace();
diff --git a/brillo/secure_allocator.h b/brillo/secure_allocator.h
index 0cbb8d9..de0b348 100644
--- a/brillo/secure_allocator.h
+++ b/brillo/secure_allocator.h
@@ -5,13 +5,51 @@
#ifndef LIBBRILLO_BRILLO_SECURE_ALLOCATOR_H_
#define LIBBRILLO_BRILLO_SECURE_ALLOCATOR_H_
+#include <errno.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include <limits>
#include <memory>
+#include <base/callback_helpers.h>
+#include <base/logging.h>
#include <brillo/brillo_export.h>
namespace brillo {
// SecureAllocator is a stateless derivation of std::allocator that clears
-// the contents of the object on deallocation.
+// the contents of the object on deallocation. Additionally, to prevent the
+// memory from being leaked, we use the following defensive mechanisms:
+//
+// 1. Use page-aligned memory so that it can be locked (therefore, use mmap()
+// instead of malloc()). Note that mlock()s are not inherited over fork(),
+//
+// 2. Always allocate memory in multiples of pages: this adds a memory overhead
+// of ~1 page for each object. Moreover, the extra memory is not available
+// for the allocated object to expand into: the container expects that the
+// memory allocated to it matches the size set in reserve().
+// TODO(sarthakkukreti): Figure out if it is possible to propagate the real
+// capacity to the container without an intrusive change to the STL.
+// [Example: allow __recommend() override in allocators for containers.]
+//
+// 3. Mark the memory segments as undumpable, unmergeable.
+//
+// 4. Use MADV_WIPEONFORK:
+// this results in a new anonymous vma instead of copying over the contents
+// of the secure object after a fork(). By default [MADV_DOFORK], the vma is
+// marked as copy-on-write, and the first process which writes to the secure
+// object after fork get a new copy. This may break the security guarantees
+// setup above. Another alternative is to use MADV_DONTFORK which results in
+// the memory mapping not getting copied over to child process at all: this
+// may result in cases where if the child process gets segmentation faults
+// on attempts to access virtual addresses in the secure object's address
+// range,
+//
+// With MADV_WIPEONFORK, the child processes can access the secure object
+// memory safely, but the contents of the secure object appear as zero to
+// the child process. Note that threads share the virtual address space and
+// secure objects would be transparent across threads.
+// TODO(sarthakkukreti): Figure out patterns to pass secure data over fork().
template <typename T>
class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> {
public:
@@ -19,21 +57,118 @@ class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> {
using typename std::allocator<T>::size_type;
using typename std::allocator<T>::value_type;
- // Implicit std::allocator constructors.
+ // Constructors that wrap over std::allocator.
+ // Make sure that the allocator's static members are only allocated once.
+ SecureAllocator() noexcept : std::allocator<T>() {}
+ SecureAllocator(const SecureAllocator& other) noexcept
+ : std::allocator<T>(other) {}
+
+ template <class U>
+ SecureAllocator(const SecureAllocator<U>& other) noexcept
+ : std::allocator<T>(other) {}
template <typename U> struct rebind {
typedef SecureAllocator<U> other;
};
- // Allocation/deallocation: use the std::allocation functions but make sure
- // that on deallocation, the contents of the element are cleared out.
- pointer allocate(size_type n, pointer = {}) {
- return std::allocator<T>::allocate(n);
+ // Return cached max_size. Deprecated in C++17, removed in C++20.
+ size_type max_size() const { return max_size_; }
+
+ // Allocation: allocate ceil(size/pagesize) for holding the data.
+ pointer allocate(size_type n, pointer hint = nullptr) {
+ pointer buffer = nullptr;
+ // Check if n can be theoretically allocated.
+ CHECK_LT(n, max_size());
+
+ // std::allocator is expected to throw a std::bad_alloc on failing to
+ // allocate the memory correctly. Instead of returning a nullptr, which
+ // confuses the standard template library, use CHECK(false) to crash on
+ // the failure path.
+ base::ScopedClosureRunner fail_on_allocation_error(base::Bind([]() {
+ PLOG(ERROR) << "Failed to allocate secure memory";
+ CHECK(false);
+ }));
+
+ // Check if n = 0: there's nothing to allocate;
+ if (n == 0)
+ return nullptr;
+
+ // Calculate the page-aligned buffer size.
+ size_type buffer_size = CalculatePageAlignedBufferSize(n);
+
+ // Memory locking granularity is per-page: mmap ceil(size/page size) pages.
+ buffer = reinterpret_cast<pointer>(
+ mmap(nullptr, buffer_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
+ if (buffer == MAP_FAILED)
+ return nullptr;
+
+ // Lock buffer into physical memory.
+ if (mlock(buffer, buffer_size)) {
+ CHECK_NE(errno, ENOMEM) << "It is likely that SecureAllocator have "
+ "exceeded the RLIMIT_MEMLOCK limit";
+ return nullptr;
+ }
+
+ // Mark memory as non dumpable in a core dump.
+ if (madvise(buffer, buffer_size, MADV_DONTDUMP))
+ return nullptr;
+
+ // Mark memory as non mergeable with another page, even if the contents
+ // are the same.
+ if (madvise(buffer, buffer_size, MADV_UNMERGEABLE)) {
+ // MADV_UNMERGEABLE is only available if the kernel has been configured
+ // with CONFIG_KSM set. If the CONFIG_KSM flag has not been set, then
+ // pages are not mergeable so this madvise option is not necessary.
+ //
+ // In the case where CONFIG_KSM is not set, EINVAL is the error set.
+ // Since this error value is expected in some cases, we don't return a
+ // nullptr.
+ if (errno != EINVAL)
+ return nullptr;
+ }
+
+ // Make this mapping available to child processes but don't copy data from
+ // the secure object's pages during fork. With MADV_DONTFORK, the
+ // vma is not mapped in the child process which leads to segmentation
+ // faults if the child process tries to access this address. For example,
+ // if the parent process creates a SecureObject, forks() and the child
+ // process tries to call the destructor at the virtual address.
+ if (madvise(buffer, buffer_size, MADV_WIPEONFORK))
+ return nullptr;
+
+ ignore_result(fail_on_allocation_error.Release());
+
+ // Allocation was successful.
+ return buffer;
+ }
+
+ // Destroy object before deallocation. Deprecated in C++17, removed in C++20.
+ // After destroying the object, clear the contents of where the object was
+ // stored.
+ template <class U>
+ void destroy(U* p) {
+ // Return if the pointer is invalid.
+ if (!p)
+ return;
+ std::allocator<U>::destroy(p);
+ clear_contents(p, sizeof(U));
}
virtual void deallocate(pointer p, size_type n) {
- clear_contents(p, n * sizeof(value_type));
- std::allocator<T>::deallocate(p, n);
+ // Check if n can be theoretically deallocated.
+ CHECK_LT(n, max_size());
+
+ // Check if n = 0 or p is a nullptr: there's nothing to deallocate;
+ if (n == 0 || !p)
+ return;
+
+ // Calculate the page-aligned buffer size.
+ size_type buffer_size = CalculatePageAlignedBufferSize(n);
+
+ clear_contents(p, buffer_size);
+ munlock(p, buffer_size);
+ munmap(p, buffer_size);
}
protected:
@@ -54,8 +189,53 @@ class BRILLO_PRIVATE SecureAllocator : public std::allocator<T> {
}
#undef __attribute_no_opt
+
+ private:
+ // Calculate the page-aligned buffer size.
+ size_t CalculatePageAlignedBufferSize(size_type n) {
+ size_type real_size = n * sizeof(value_type);
+ size_type page_aligned_remainder = real_size % page_size_;
+ size_type padding =
+ page_aligned_remainder != 0 ? page_size_ - page_aligned_remainder : 0;
+ return real_size + padding;
+ }
+
+ static size_t CalculatePageSize() {
+ long ret = sysconf(_SC_PAGESIZE); // NOLINT [runtime/int]
+
+ // Initialize page size.
+ CHECK_GT(ret, 0L);
+ return ret;
+ }
+
+ // Since the allocator reuses page size and max size consistently,
+ // cache these values initially and reuse.
+ static size_t GetMaxSizeForType(size_t page_size) {
+ // Initialize max size that can be theoretically allocated.
+ // Calculate the max size that is page-aligned.
+ size_t max_theoretical_size = std::numeric_limits<size_type>::max();
+ size_t max_page_aligned_size =
+ max_theoretical_size - (max_theoretical_size % page_size);
+
+ return max_page_aligned_size / sizeof(value_type);
+ }
+
+ // Page size on system.
+ static const size_type page_size_;
+ // Max theoretical count for type on system.
+ static const size_type max_size_;
};
+// Inline definitions are only allowed for static const members with integral
+// constexpr initializers, define static members of SecureAllocator types here.
+template <typename T>
+const typename SecureAllocator<T>::size_type SecureAllocator<T>::page_size_ =
+ SecureAllocator<T>::CalculatePageSize();
+
+template <typename T>
+const typename SecureAllocator<T>::size_type SecureAllocator<T>::max_size_ =
+ SecureAllocator<T>::GetMaxSizeForType(SecureAllocator<T>::page_size_);
+
} // namespace brillo
#endif // LIBBRILLO_BRILLO_SECURE_ALLOCATOR_H_
diff --git a/brillo/secure_blob_test.cc b/brillo/secure_blob_test.cc
index 75f3cfb..7242e86 100644
--- a/brillo/secure_blob_test.cc
+++ b/brillo/secure_blob_test.cc
@@ -234,16 +234,18 @@ class TestSecureAllocator : public SecureAllocator<T> {
public:
using typename SecureAllocator<T>::pointer;
using typename SecureAllocator<T>::size_type;
+ using typename SecureAllocator<T>::value_type;
int GetErasedCount() { return erased_count; }
protected:
void clear_contents(pointer p, size_type n) override {
SecureAllocator<T>::clear_contents(p, n);
+ unsigned char *v = reinterpret_cast<unsigned char*>(p);
for (int i = 0; i < n; i++) {
- EXPECT_EQ(p[i], 0);
+ EXPECT_EQ(v[i], 0);
+ erased_count++;
}
- erased_count++;
}
private:
@@ -259,7 +261,54 @@ TEST(SecureAllocator, ErasureOnDeallocation) {
// Deallocate memory; the mock class should check for cleared data.
e.deallocate(test_string_addr, 15);
- EXPECT_EQ(e.GetErasedCount(), 1);
+ // The deallocation should have traversed the complete page.
+ EXPECT_EQ(e.GetErasedCount(), 4096);
}
+TEST(SecureAllocator, MultiPageCorrectness) {
+ // Make sure that the contents are cleared on deallocation.
+ TestSecureAllocator<uint64_t> e;
+
+ // Allocate 4100*8 bytes.
+ uint64_t *test_array = e.allocate(4100);
+
+ // Check if the space was correctly allocated for long long.
+ for (int i = 0; i < 4100; i++)
+ test_array[i] = 0xF0F0F0F0F0F0F0F0;
+
+ // Deallocate memory; the mock class should check for cleared data.
+ e.deallocate(test_array, 4100);
+ // 36864 bytes is the next highest size that is a multiple of the page size.
+ EXPECT_EQ(e.GetErasedCount(), 36864);
+}
+
+// DeathTests fork a new process and check how it proceeds. Take advantage
+// of this and check if the value of SecureString is passed on to
+// forked children.
+#if GTEST_IS_THREADSAFE
+// Check if the contents of the container are zeroed out.
+void CheckPropagationOnFork(const brillo::SecureBlob& forked_blob,
+ const Blob& reference) {
+ LOG(INFO) << forked_blob.to_string();
+ for (int i = 0; i < forked_blob.size(); i++) {
+ CHECK_NE(reference[i], forked_blob[i]);
+ CHECK_EQ(forked_blob[i], 0);
+ }
+ exit(0);
+}
+
+TEST(SecureAllocatorDeathTest, ErasureOnFork) {
+ Blob reference = BlobFromString("Test String");
+ SecureBlob erasable_blob(reference.begin(), reference.end());
+
+ EXPECT_EXIT(CheckPropagationOnFork(erasable_blob, reference),
+ ::testing::ExitedWithCode(0), "");
+
+ // In the original process, check the SecureBlob to see if it has not
+ // changed.
+ for (int i = 0; i < erasable_blob.size(); i++)
+ EXPECT_EQ(erasable_blob[i], reference[i]);
+}
+#endif // GTEST_IS_THREADSAFE
+
} // namespace brillo
diff --git a/brillo/streams/file_stream.cc b/brillo/streams/file_stream.cc
index db22192..70b25dd 100644
--- a/brillo/streams/file_stream.cc
+++ b/brillo/streams/file_stream.cc
@@ -12,6 +12,7 @@
#include <utility>
#include <base/bind.h>
+#include <base/files/file_descriptor_watcher_posix.h>
#include <base/files/file_util.h>
#include <base/posix/eintr_wrapper.h>
#include <brillo/errors/error_codes.h>
@@ -86,15 +87,11 @@ class FileDescriptor : public FileStream::FileDescriptorInterface {
ErrorPtr* error) override {
if (stream_utils::IsReadAccessMode(mode)) {
CHECK(read_data_callback_.is_null());
- MessageLoop::current()->CancelTask(read_watcher_);
- read_watcher_ = MessageLoop::current()->WatchFileDescriptor(
- FROM_HERE,
+ read_watcher_ = base::FileDescriptorWatcher::WatchReadable(
fd_,
- MessageLoop::WatchMode::kWatchRead,
- false, // persistent
- base::Bind(&FileDescriptor::OnFileCanReadWithoutBlocking,
- base::Unretained(this)));
- if (read_watcher_ == MessageLoop::kTaskIdNull) {
+ base::BindRepeating(&FileDescriptor::OnReadable,
+ base::Unretained(this)));
+ if (!read_watcher_) {
Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
errors::stream::kInvalidParameter,
"File descriptor doesn't support watching for reading.");
@@ -104,15 +101,11 @@ class FileDescriptor : public FileStream::FileDescriptorInterface {
}
if (stream_utils::IsWriteAccessMode(mode)) {
CHECK(write_data_callback_.is_null());
- MessageLoop::current()->CancelTask(write_watcher_);
- write_watcher_ = MessageLoop::current()->WatchFileDescriptor(
- FROM_HERE,
+ write_watcher_ = base::FileDescriptorWatcher::WatchWritable(
fd_,
- MessageLoop::WatchMode::kWatchWrite,
- false, // persistent
- base::Bind(&FileDescriptor::OnFileCanWriteWithoutBlocking,
- base::Unretained(this)));
- if (write_watcher_ == MessageLoop::kTaskIdNull) {
+ base::BindRepeating(&FileDescriptor::OnWritable,
+ base::Unretained(this)));
+ if (!write_watcher_) {
Error::AddTo(error, FROM_HERE, errors::stream::kDomain,
errors::stream::kInvalidParameter,
"File descriptor doesn't support watching for writing.");
@@ -157,31 +150,26 @@ class FileDescriptor : public FileStream::FileDescriptorInterface {
void CancelPendingAsyncOperations() override {
read_data_callback_.Reset();
- if (read_watcher_ != MessageLoop::kTaskIdNull) {
- MessageLoop::current()->CancelTask(read_watcher_);
- read_watcher_ = MessageLoop::kTaskIdNull;
- }
-
+ read_watcher_ = nullptr;
write_data_callback_.Reset();
- if (write_watcher_ != MessageLoop::kTaskIdNull) {
- MessageLoop::current()->CancelTask(write_watcher_);
- write_watcher_ = MessageLoop::kTaskIdNull;
- }
+ write_watcher_ = nullptr;
}
// Called from the brillo::MessageLoop when the file descriptor is available
// for reading.
- void OnFileCanReadWithoutBlocking() {
+ void OnReadable() {
CHECK(!read_data_callback_.is_null());
- DataCallback cb = read_data_callback_;
- read_data_callback_.Reset();
+
+ read_watcher_ = nullptr;
+ DataCallback cb = std::move(read_data_callback_);
cb.Run(Stream::AccessMode::READ);
}
- void OnFileCanWriteWithoutBlocking() {
+ void OnWritable() {
CHECK(!write_data_callback_.is_null());
- DataCallback cb = write_data_callback_;
- write_data_callback_.Reset();
+
+ write_watcher_ = nullptr;
+ DataCallback cb = std::move(write_data_callback_);
cb.Run(Stream::AccessMode::WRITE);
}
@@ -200,9 +188,9 @@ class FileDescriptor : public FileStream::FileDescriptorInterface {
DataCallback read_data_callback_;
DataCallback write_data_callback_;
- // MessageLoop tasks monitoring read/write operations on the file descriptor.
- MessageLoop::TaskId read_watcher_{MessageLoop::kTaskIdNull};
- MessageLoop::TaskId write_watcher_{MessageLoop::kTaskIdNull};
+ // Monitoring read/write operations on the file descriptor.
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> read_watcher_;
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> write_watcher_;
DISALLOW_COPY_AND_ASSIGN(FileDescriptor);
};
diff --git a/brillo/streams/file_stream_test.cc b/brillo/streams/file_stream_test.cc
index 23ef64c..36bad07 100644
--- a/brillo/streams/file_stream_test.cc
+++ b/brillo/streams/file_stream_test.cc
@@ -25,6 +25,7 @@
#include <gmock/gmock.h>
#include <gtest/gtest.h>
+using testing::DoAll;
using testing::InSequence;
using testing::Return;
using testing::ReturnArg;
diff --git a/brillo/streams/input_stream_set.cc b/brillo/streams/input_stream_set.cc
index 0ceb5b4..847bf05 100644
--- a/brillo/streams/input_stream_set.cc
+++ b/brillo/streams/input_stream_set.cc
@@ -172,7 +172,7 @@ bool InputStreamSet::WaitForData(
return stream->WaitForData(mode, callback, error);
}
- MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, mode));
+ MessageLoop::current()->PostTask(FROM_HERE, base::BindOnce(callback, mode));
return true;
}
diff --git a/brillo/streams/memory_stream.cc b/brillo/streams/memory_stream.cc
index 54f127a..f4f9cca 100644
--- a/brillo/streams/memory_stream.cc
+++ b/brillo/streams/memory_stream.cc
@@ -185,7 +185,7 @@ bool MemoryStream::CheckContainer(ErrorPtr* error) const {
bool MemoryStream::WaitForData(AccessMode mode,
const base::Callback<void(AccessMode)>& callback,
ErrorPtr* /* error */) {
- MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, mode));
+ MessageLoop::current()->PostTask(FROM_HERE, base::BindOnce(callback, mode));
return true;
}
diff --git a/brillo/streams/stream.cc b/brillo/streams/stream.cc
index 6a40c00..80f2df4 100644
--- a/brillo/streams/stream.cc
+++ b/brillo/streams/stream.cc
@@ -213,8 +213,9 @@ bool Stream::ReadAsyncImpl(
if (force_async_callback) {
MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&Stream::OnReadAsyncDone, weak_ptr_factory_.GetWeakPtr(),
- success_callback, read, eos));
+ base::BindOnce(&Stream::OnReadAsyncDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ success_callback, read, eos));
} else {
is_async_read_pending_ = false;
success_callback.Run(read, eos);
@@ -277,8 +278,9 @@ bool Stream::WriteAsyncImpl(
if (force_async_callback) {
MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&Stream::OnWriteAsyncDone, weak_ptr_factory_.GetWeakPtr(),
- success_callback, written));
+ base::BindOnce(&Stream::OnWriteAsyncDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ success_callback, written));
} else {
is_async_write_pending_ = false;
success_callback.Run(written);
diff --git a/brillo/streams/stream_utils.cc b/brillo/streams/stream_utils.cc
index 6f8a1d0..5029e3a 100644
--- a/brillo/streams/stream_utils.cc
+++ b/brillo/streams/stream_utils.cc
@@ -213,7 +213,7 @@ void CopyData(StreamPtr in_stream,
state->success_callback = success_callback;
state->error_callback = error_callback;
brillo::MessageLoop::current()->PostTask(FROM_HERE,
- base::Bind(&PerformRead, state));
+ base::BindOnce(&PerformRead, state));
}
} // namespace stream_utils
diff --git a/brillo/streams/stream_utils_test.cc b/brillo/streams/stream_utils_test.cc
index e0b327d..50fb67e 100644
--- a/brillo/streams/stream_utils_test.cc
+++ b/brillo/streams/stream_utils_test.cc
@@ -25,7 +25,7 @@ ACTION_TEMPLATE(InvokeAsyncCallback,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(size)) {
brillo::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(std::get<k>(args), size));
+ FROM_HERE, base::BindOnce(std::get<k>(args), size));
return true;
}
@@ -42,7 +42,8 @@ ACTION_TEMPLATE(InvokeAsyncErrorCallback,
brillo::ErrorPtr error;
brillo::Error::AddTo(&error, FROM_HERE, "test", code, "message");
brillo::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(std::get<k>(args), base::Owned(error.release())));
+ FROM_HERE, base::BindOnce(std::get<k>(args),
+ base::Owned(error.release())));
return true;
}
diff --git a/brillo/streams/tls_stream.cc b/brillo/streams/tls_stream.cc
index cc63258..4b8a227 100644
--- a/brillo/streams/tls_stream.cc
+++ b/brillo/streams/tls_stream.cc
@@ -393,10 +393,10 @@ bool TlsStream::TlsStreamImpl::Init(StreamPtr socket,
if (MessageLoop::ThreadHasCurrent()) {
MessageLoop::current()->PostTask(
FROM_HERE,
- base::Bind(&TlsStreamImpl::DoHandshake,
- weak_ptr_factory_.GetWeakPtr(),
- success_callback,
- error_callback));
+ base::BindOnce(&TlsStreamImpl::DoHandshake,
+ weak_ptr_factory_.GetWeakPtr(),
+ success_callback,
+ error_callback));
} else {
DoHandshake(success_callback, error_callback);
}
diff --git a/brillo/timezone/EST_test.tzif b/brillo/timezone/EST_test.tzif
new file mode 100644
index 0000000..ae34663
--- /dev/null
+++ b/brillo/timezone/EST_test.tzif
Binary files differ
diff --git a/brillo/timezone/Indian_Christmas_test.tzif b/brillo/timezone/Indian_Christmas_test.tzif
new file mode 100644
index 0000000..066c1e9
--- /dev/null
+++ b/brillo/timezone/Indian_Christmas_test.tzif
Binary files differ
diff --git a/brillo/timezone/Pacific_Fiji_test.tzif b/brillo/timezone/Pacific_Fiji_test.tzif
new file mode 100644
index 0000000..76ae63e
--- /dev/null
+++ b/brillo/timezone/Pacific_Fiji_test.tzif
Binary files differ
diff --git a/brillo/timezone/tzif_parser.cc b/brillo/timezone/tzif_parser.cc
new file mode 100644
index 0000000..5756196
--- /dev/null
+++ b/brillo/timezone/tzif_parser.cc
@@ -0,0 +1,164 @@
+// Copyright 2018 The Chromium OS 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 "brillo/timezone/tzif_parser.h"
+
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string.h>
+#include <utility>
+#include <vector>
+
+#include <base/files/file.h>
+#include <base/files/file_path.h>
+#include <base/logging.h>
+#include <base/stl_util.h>
+#include <base/strings/string_util.h>
+
+namespace {
+
+struct tzif_header {
+ char magic[4];
+ char version;
+ char reserved[15];
+ int32_t ttisgmtcnt;
+ int32_t ttisstdcnt;
+ int32_t leapcnt;
+ int32_t timecnt;
+ int32_t typecnt;
+ int32_t charcnt;
+};
+
+bool ReadInt(base::File* file, int32_t* out_int) {
+ DCHECK(out_int);
+ int32_t buf;
+ int read = file->ReadAtCurrentPos(reinterpret_cast<char*>(&buf), sizeof(buf));
+ if (read != sizeof(buf)) {
+ return false;
+ }
+ // Values are stored in network byte order (highest-order byte first).
+ // We probably need to convert them to match the endianness of our system.
+ *out_int = ntohl(buf);
+ return true;
+}
+
+bool ParseTzifHeader(base::File* tzfile, struct tzif_header* header) {
+ DCHECK(header);
+ int read = tzfile->ReadAtCurrentPos(header->magic, sizeof(header->magic));
+ if (read != sizeof(header->magic)) {
+ return false;
+ }
+ if (memcmp(header->magic, "TZif", 4) != 0) {
+ return false;
+ }
+
+ read = tzfile->ReadAtCurrentPos(&header->version, sizeof(header->version));
+ if (read != sizeof(header->version)) {
+ return false;
+ }
+ if (header->version != '\0' && header->version != '2' &&
+ header->version != '3') {
+ return false;
+ }
+
+ read = tzfile->ReadAtCurrentPos(header->reserved, sizeof(header->reserved));
+ if (read != sizeof(header->reserved)) {
+ return false;
+ }
+ for (size_t i = 0; i < sizeof(header->reserved); i++) {
+ if (header->reserved[i] != 0) {
+ return false;
+ }
+ }
+
+ if (!ReadInt(tzfile, &header->ttisgmtcnt) || header->ttisgmtcnt < 0) {
+ return false;
+ }
+ if (!ReadInt(tzfile, &header->ttisstdcnt) || header->ttisstdcnt < 0) {
+ return false;
+ }
+ if (!ReadInt(tzfile, &header->leapcnt) || header->leapcnt < 0) {
+ return false;
+ }
+ if (!ReadInt(tzfile, &header->timecnt) || header->timecnt < 0) {
+ return false;
+ }
+ if (!ReadInt(tzfile, &header->typecnt) || header->typecnt < 0) {
+ return false;
+ }
+ if (!ReadInt(tzfile, &header->charcnt) || header->charcnt < 0) {
+ return false;
+ }
+ return true;
+}
+
+} // namespace
+
+namespace brillo {
+
+namespace timezone {
+
+base::Optional<std::string> GetPosixTimezone(const base::FilePath& tzif_path) {
+ base::FilePath to_parse;
+ if (tzif_path.IsAbsolute()) {
+ to_parse = tzif_path;
+ } else {
+ to_parse = base::FilePath("/usr/share/zoneinfo").Append(tzif_path);
+ }
+ base::File tzfile(to_parse, base::File::FLAG_OPEN | base::File::FLAG_READ);
+ struct tzif_header first_header;
+ if (!tzfile.IsValid() || !ParseTzifHeader(&tzfile, &first_header)) {
+ return base::nullopt;
+ }
+
+ if (first_header.version == '\0') {
+ // Generating a POSIX-style TZ string from a TZif version 1 file is hard;
+ // TZ strings need relative dates (1st Sunday in March, 1st Sunday in Nov,
+ // etc.), but the version 1 files only give absolute dates for each
+ // year up to 2037. Fortunately version 1 files are no longer created by
+ // the newer versions of the timezone-data package.
+ //
+ // Because of this, we're not going to try and handle this, and instead just
+ // return an error.
+ return base::nullopt;
+ }
+
+ // TZif versions 2 and 3 embed a POSIX-style TZ string after their
+ // contents. We read that out and return it.
+
+ // Skip past the first body section and all of the second section. See
+ // 'man tzfile' for an explanation of these offset values.
+ int64_t first_body_size =
+ 4 * first_header.timecnt + 1 * first_header.timecnt +
+ (4 + 1 + 1) * first_header.typecnt + 1 * first_header.charcnt +
+ (4 + 4) * first_header.leapcnt + 1 * first_header.ttisstdcnt +
+ 1 * first_header.ttisgmtcnt;
+ tzfile.Seek(base::File::FROM_CURRENT, first_body_size);
+
+ struct tzif_header second_header;
+ if (!ParseTzifHeader(&tzfile, &second_header)) {
+ return base::nullopt;
+ }
+
+ int64_t second_body_size =
+ 8 * second_header.timecnt + 1 * second_header.timecnt +
+ (4 + 1 + 1) * second_header.typecnt + 1 * second_header.charcnt +
+ (8 + 4) * second_header.leapcnt + 1 * second_header.ttisstdcnt +
+ 1 * second_header.ttisgmtcnt;
+ int64_t offset = tzfile.Seek(base::File::FROM_CURRENT, second_body_size);
+
+ std::string time_string(tzfile.GetLength() - offset, '\0');
+ if (tzfile.ReadAtCurrentPos(base::data(time_string), time_string.size()) !=
+ time_string.size()) {
+ return base::nullopt;
+ }
+
+ // According to the spec, the embedded string is enclosed by '\n' characters.
+ base::TrimWhitespaceASCII(time_string, base::TRIM_ALL, &time_string);
+ return std::move(time_string);
+}
+
+} // namespace timezone
+
+} // namespace brillo
diff --git a/brillo/timezone/tzif_parser.h b/brillo/timezone/tzif_parser.h
new file mode 100644
index 0000000..058079c
--- /dev/null
+++ b/brillo/timezone/tzif_parser.h
@@ -0,0 +1,29 @@
+// Copyright 2020 The Chromium OS 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 LIBBRILLO_BRILLO_TIMEZONE_TZIF_PARSER_H_
+#define LIBBRILLO_BRILLO_TIMEZONE_TZIF_PARSER_H_
+
+#include <string>
+
+#include <base/files/file_path.h>
+#include <base/optional.h>
+#include <brillo/brillo_export.h>
+
+namespace brillo {
+
+namespace timezone {
+
+// GetPosixTimezone takes a path to a tzfile, and returns the POSIX timezone in
+// a string. See 'man tzfile' for more info on the format. If |tzif_path| is a
+// relative path, it will be appended to /usr/share/zoneinfo/, otherwise
+// |tzif_path| as an absolute path will be used directly.
+base::Optional<std::string> BRILLO_EXPORT GetPosixTimezone(
+ const base::FilePath& tzif_path);
+
+} // namespace timezone
+
+} // namespace brillo
+
+#endif // LIBBRILLO_BRILLO_TIMEZONE_TZIF_PARSER_H_
diff --git a/brillo/timezone/tzif_parser_test.cc b/brillo/timezone/tzif_parser_test.cc
new file mode 100644
index 0000000..305da4d
--- /dev/null
+++ b/brillo/timezone/tzif_parser_test.cc
@@ -0,0 +1,46 @@
+// Copyright 2018 The Chromium OS 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 <stdlib.h>
+
+#include <base/files/file_path.h>
+#include <gtest/gtest.h>
+
+#include "brillo/timezone/tzif_parser.h"
+
+namespace brillo {
+
+namespace timezone {
+
+class TzifParserTest : public ::testing::Test {
+ public:
+ TzifParserTest() {
+ source_dir_ =
+ base::FilePath(getenv("SRC")).Append("brillo").Append("timezone");
+ }
+
+ protected:
+ base::FilePath source_dir_;
+};
+
+TEST_F(TzifParserTest, EST) {
+ auto posix_result = GetPosixTimezone(source_dir_.Append("EST_test.tzif"));
+ EXPECT_EQ(posix_result, "EST5");
+}
+
+TEST_F(TzifParserTest, TzifVersionTwo) {
+ auto posix_result =
+ GetPosixTimezone(source_dir_.Append("Indian_Christmas_test.tzif"));
+ EXPECT_EQ(posix_result, "<+07>-7");
+}
+
+TEST_F(TzifParserTest, TzifVersionThree) {
+ auto posix_result =
+ GetPosixTimezone(source_dir_.Append("Pacific_Fiji_test.tzif"));
+ EXPECT_EQ(posix_result, "<+12>-12<+13>,M11.1.0,M1.2.2/123");
+}
+
+} // namespace timezone
+
+} // namespace brillo
diff --git a/brillo/type_list.h b/brillo/type_list.h
index c5ccc5e..b14ef1e 100644
--- a/brillo/type_list.h
+++ b/brillo/type_list.h
@@ -48,6 +48,22 @@ template <typename T, typename Types>
using EnableIfIsOneOf =
std::enable_if_t<type_list::is_one_of<T, Types>::value>;
+// Enables a template if the type T is in the typelist Types and T is an
+// arithmetic type (some sort of int or floating-point number).
+template <typename T, typename Types>
+using EnableIfIsOneOfArithmetic =
+ std::enable_if_t<std::is_arithmetic<T>::value &&
+ type_list::is_one_of<T, Types>::value,
+ int>;
+
+// Enables a template if the type T is in the typelist Types and T is not an
+// arithmetic type (is void, nullptr_t, or a non-fundamental type).
+template <typename T, typename Types>
+using EnableIfIsOneOfNonArithmetic =
+ std::enable_if_t<!std::is_arithmetic<T>::value &&
+ type_list::is_one_of<T, Types>::value,
+ int>;
+
} // namespace brillo
#endif // LIBBRILLO_BRILLO_TYPE_LIST_H_
diff --git a/policy/OWNERS b/policy/OWNERS
index 0208469..74cea9e 100644
--- a/policy/OWNERS
+++ b/policy/OWNERS
@@ -1,5 +1,4 @@
emaxx@chromium.org
-ljusten@chromium.org
pmarko@chromium.org
poromov@chromium.org
rsorokin@chromium.org
diff --git a/policy/device_policy_impl.cc b/policy/device_policy_impl.cc
index 72d30b1..54ea1f9 100644
--- a/policy/device_policy_impl.cc
+++ b/policy/device_policy_impl.cc
@@ -16,6 +16,7 @@
#include <base/logging.h>
#include <base/macros.h>
#include <base/memory/ptr_util.h>
+#include <base/stl_util.h>
#include <base/time/time.h>
#include <base/values.h>
#include <openssl/evp.h>
@@ -100,7 +101,7 @@ std::string DecodeConnectionType(int type) {
"ethernet", "wifi", "wimax", "bluetooth", "cellular",
};
- if (type < 0 || type >= static_cast<int>(arraysize(kConnectionTypes)))
+ if (type < 0 || type >= static_cast<int>(base::size(kConnectionTypes)))
return std::string();
return kConnectionTypes[type];