summaryrefslogtreecommitdiffstats
path: root/libchrome_tools
diff options
context:
space:
mode:
authorQijiang Fan <fqj@google.com>2020-07-03 13:58:01 +0900
committerQijiang Fan <fqj@google.com>2020-07-03 14:51:37 +0900
commitedddb73384356911190b33bbce56ffacedc85da2 (patch)
tree9f9a743354cc3f458775ae19e39804a553d5bbbd /libchrome_tools
parentcc7f6386fd653c2da4daf75bf1584c753affd5a4 (diff)
parent2fa400214c4a9acca292b649bf060f3f87f32f14 (diff)
downloadplatform_external_libchrome-edddb73384356911190b33bbce56ffacedc85da2.tar.gz
platform_external_libchrome-edddb73384356911190b33bbce56ffacedc85da2.tar.bz2
platform_external_libchrome-edddb73384356911190b33bbce56ffacedc85da2.zip
Reconnect history from Chromium OS libchromeandroid-r-beta-3android-r-beta-2
Bug: chromium:1048062, chromium:915258 Test: Presubmit Change-Id: Ib99ccd945f3ff2d1a1ceba98cb8d7a53d0d9c075
Diffstat (limited to 'libchrome_tools')
-rwxr-xr-xlibchrome_tools/files_not_built16
-rwxr-xr-xlibchrome_tools/include_generator.py93
-rwxr-xr-xlibchrome_tools/jni_generator_helper.sh42
-rwxr-xr-xlibchrome_tools/jni_registration_generator_helper.sh40
-rwxr-xr-xlibchrome_tools/mojom_generate_type_mappings.py108
-rw-r--r--libchrome_tools/patch/0001-Use-qualified-base-make_optional-in-optional_unittes.patch102
-rw-r--r--libchrome_tools/patch/580fcef.patch112
-rw-r--r--libchrome_tools/patch/8fbafc9.patch25
-rw-r--r--libchrome_tools/patch/ContextUtils.patch18
-rw-r--r--libchrome_tools/patch/ThreadLocalStorage-Add-a-function-to-destroy-pthread.patch63
-rw-r--r--libchrome_tools/patch/alignof_int64.patch88
-rw-r--r--libchrome_tools/patch/allocator_shim.patch13
-rw-r--r--libchrome_tools/patch/ashmem.patch20
-rw-r--r--libchrome_tools/patch/build_config.patch53
-rw-r--r--libchrome_tools/patch/build_time.patch74
-rw-r--r--libchrome_tools/patch/buildflag_header.patch97
-rw-r--r--libchrome_tools/patch/c7ce19d.patch28
-rw-r--r--libchrome_tools/patch/compiler_specific.patch16
-rw-r--r--libchrome_tools/patch/dmg_fp.patch160
-rw-r--r--libchrome_tools/patch/file_path_mojom.patch19
-rw-r--r--libchrome_tools/patch/file_posix.patch24
-rw-r--r--libchrome_tools/patch/gmock.patch6
-rw-r--r--libchrome_tools/patch/gtest.patch10
-rw-r--r--libchrome_tools/patch/handle_table.patch176
-rw-r--r--libchrome_tools/patch/hash.patch21
-rw-r--r--libchrome_tools/patch/jni_registration_generator.patch13
-rw-r--r--libchrome_tools/patch/libevent.patch13
-rw-r--r--libchrome_tools/patch/logging.patch78
-rw-r--r--libchrome_tools/patch/macros.patch72
-rw-r--r--libchrome_tools/patch/memory_linux.patch17
-rw-r--r--libchrome_tools/patch/message_loop.patch23
-rw-r--r--libchrome_tools/patch/message_loop_unittest.patch125
-rw-r--r--libchrome_tools/patch/message_pump_for_ui.patch28
-rw-r--r--libchrome_tools/patch/modp_b64.patch19
-rw-r--r--libchrome_tools/patch/mojo-Add-a-way-to-create-thread-safe-interfaces-in-Java.patch137
-rw-r--r--libchrome_tools/patch/mojo.patch38
-rw-r--r--libchrome_tools/patch/mojom_disable_trace_and_mem_dump.patch299
-rw-r--r--libchrome_tools/patch/observer_list_unittest.patch65
-rw-r--r--libchrome_tools/patch/path_service.patch83
-rw-r--r--libchrome_tools/patch/protobuf.patch4
-rw-r--r--libchrome_tools/patch/shared_memory_handle.patch22
-rw-r--r--libchrome_tools/patch/shared_memory_mapping.patch33
-rw-r--r--libchrome_tools/patch/shared_memory_posix.patch90
-rw-r--r--libchrome_tools/patch/ssl.patch82
-rw-r--r--libchrome_tools/patch/statfs_f_type.patch40
-rw-r--r--libchrome_tools/patch/subprocess.patch74
-rw-r--r--libchrome_tools/patch/symbolize.patch18
-rw-r--r--libchrome_tools/patch/task_annotator.patch12
-rw-r--r--libchrome_tools/patch/trace_event.patch191
-rw-r--r--libchrome_tools/patch/values.patch63
-rw-r--r--libchrome_tools/patch/virtual_destructor.patch78
-rw-r--r--libchrome_tools/patches/Add-base-NoDestructor-T.patch129
-rw-r--r--libchrome_tools/patches/Add-header-files-base-check_op-notreached-h.patch48
-rw-r--r--libchrome_tools/patches/Connect-to-NameOwnerChanged-signal-when-setting-call.patch163
-rw-r--r--libchrome_tools/patches/Fix-TimeDelta.patch164
-rw-r--r--libchrome_tools/patches/Fix-Wdefaulted-function-deleted-warning-in-MessageLo.patch38
-rw-r--r--libchrome_tools/patches/Mojo-Check-if-dispatcher-is-null-in-Core-UnwrapPlatf.patch38
-rw-r--r--libchrome_tools/patches/Refactor-AlarmTimer-to-report-error-to-the-caller.patch180
-rw-r--r--libchrome_tools/patches/WaitForServiceToBeAvailable.patch45
-rw-r--r--libchrome_tools/patches/components-timers-fix-fd-leak-in-AlarmTimer.patch102
-rw-r--r--libchrome_tools/patches/dbus-Add-TryRegisterFallback.patch137
-rw-r--r--libchrome_tools/patches/dbus-Make-Bus-is_connected-mockable.patch93
-rw-r--r--libchrome_tools/patches/dbus-Remove-LOG-ERROR-in-ObjectProxy.patch58
-rw-r--r--libchrome_tools/patches/dbus-Support-UnexportMethod-from-an-exported-object.patch194
-rw-r--r--libchrome_tools/patches/enable-location-source.patch26
-rw-r--r--libchrome_tools/patches/fix-fd-watcher-leak.patch188
-rw-r--r--libchrome_tools/patches/libchrome-Add-EmptyResponseCallback-for-backward-com.patch42
-rw-r--r--libchrome_tools/patches/libchrome-Introduce-stub-ConvertableToTraceFormat.patch55
-rw-r--r--libchrome_tools/patches/libchrome-Remove-glib-dependency.patch31
-rw-r--r--libchrome_tools/patches/libchrome-Unpatch-sys.path-update.patch41
-rw-r--r--libchrome_tools/patches/libchrome-Update-crypto.patch182
-rw-r--r--libchrome_tools/patches/libchrome-fix-integer-overflow-if-microseconds-is-IN.patch27
-rw-r--r--libchrome_tools/patches/patches72
-rw-r--r--libchrome_tools/patches/r680000-forward-compatibility-patch-part-1.patch222
-rw-r--r--libchrome_tools/patches/r680000-forward-compatibility-patch-part-2.patch94
-rw-r--r--libchrome_tools/update_libchrome.py212
-rwxr-xr-xlibchrome_tools/uprev/copy_new_files.py74
-rwxr-xr-xlibchrome_tools/uprev/dirty_uprev.py69
-rw-r--r--libchrome_tools/uprev/filtered_utils.py108
-rw-r--r--libchrome_tools/uprev/filters.py129
-rwxr-xr-xlibchrome_tools/uprev/generate_filtered_tree.py257
-rw-r--r--libchrome_tools/uprev/lazytree.py169
-rwxr-xr-xlibchrome_tools/uprev/reconnect_history.py333
-rw-r--r--libchrome_tools/uprev/utils.py261
84 files changed, 7122 insertions, 0 deletions
diff --git a/libchrome_tools/files_not_built b/libchrome_tools/files_not_built
new file mode 100755
index 000000000..64ad444f6
--- /dev/null
+++ b/libchrome_tools/files_not_built
@@ -0,0 +1,16 @@
+#!/bin/bash
+# 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.
+#
+# List cc files not in BUILD.gn, and not excluded by patterns in BUILD.IGNORE
+# This list can be run by human for sanity check that no imporant things are
+# ignored after each uprev.
+
+cd $(dirname $0)/..
+find . -name '*.cc' \
+ | sed -e 's/^\.\///g' \
+ | xargs -n 1 -P 1 bash -c \
+ 'for i in $(cat BUILD.IGNORE); do grep $i <(echo $0) >/dev/null && exit; done; echo $0' \
+ | xargs -n 1 -P 1 sh -c 'grep $0 BUILD.gn >/dev/null || echo $0'
+
diff --git a/libchrome_tools/include_generator.py b/libchrome_tools/include_generator.py
new file mode 100755
index 000000000..4c115de25
--- /dev/null
+++ b/libchrome_tools/include_generator.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Generates wrapped include files to workaround -Wunused-parameter errors.
+
+In Chrome repository, "-Wunused-parameter" is disabled, and several header
+files in Chrome repository have actually unused-parameter.
+One of the typical scenarios is; in Chrome, Observer class is often defined
+as follows:
+
+class Foo {
+ public:
+ class Observer {
+ public:
+ virtual void OnSomeEvent(EventArg arg) {}
+ virtual void OnAnotherEvent(EventArg arg) {}
+ ...
+ };
+ ...
+};
+
+Here, On...Event() methods do nothing by default, and subclasses will override
+only necessary ones.
+In this use case, argument names can also work as documentation, and overrides
+can use these good interface-defined default names as a starting point for
+their implementation.
+
+On the other hand, in Android, -Wunused-parameter is enabled by default.
+Thus, if such a project includes header files from libchrome, it could cause
+a compile error (by the warning and "-Werror").
+
+To avoid such a situation, libchrome exports include files wrapped by the
+pragmas as follows.
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+${actual_include_file_content}
+#pragma GCC diagnostic pop
+
+so, the unused-parameter warning generated by the libchrome include headers
+will be ignored.
+Note that these GCC pragmas are also supported by clang for compatibility. cf)
+https://clang.llvm.org/docs/UsersManual.html#controlling-diagnostics-via-pragmas
+
+Usage: include_generator.py $(in) $(out)
+"""
+
+import sys
+
+
+def _generate(input_path, output_path):
+ """Generates a include file wrapped by pragmas.
+
+ Reads the file at |input_path| and output the content with wrapping by
+ #pragma to ignore unused-parameter warning into the file at |output_path|.
+ If the parent directories of |output_path| do not exist, creates them.
+
+ Args:
+ input_path: Path to the source file. Expected this is a chrome's header
+ file.
+ output_path: Path to the output file.
+ """
+ with open(input_path, 'r') as f:
+ content = f.read()
+
+ with open(output_path, 'w') as f:
+ f.writelines([
+ '// Generated by %s\n' % sys.argv[0],
+ '#pragma GCC diagnostic push\n'
+ '#pragma GCC diagnostic ignored "-Wunused-parameter"\n',
+ content,
+ '#pragma GCC diagnostic pop\n'])
+
+
+def main():
+ _generate(*sys.argv[1:])
+
+
+if __name__ == '__main__':
+ main()
diff --git a/libchrome_tools/jni_generator_helper.sh b/libchrome_tools/jni_generator_helper.sh
new file mode 100755
index 000000000..d610801e9
--- /dev/null
+++ b/libchrome_tools/jni_generator_helper.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Generates jni.
+
+set -e
+
+args=()
+files=()
+
+jni_generator=''
+
+for arg in "$@"; do
+ case "${arg}" in
+ --jni_generator=*)
+ jni_generator=${arg#'--jni_generator='}
+ ;;
+ --*)
+ args=("${args[@]}" "${arg}")
+ ;;
+ *)
+ files=("${files[@]}" "${arg}")
+ ;;
+ esac
+done
+
+for file in "${files[@]}"; do
+ "${jni_generator}" "${args[@]}" --input_file="${file}"
+done
diff --git a/libchrome_tools/jni_registration_generator_helper.sh b/libchrome_tools/jni_registration_generator_helper.sh
new file mode 100755
index 000000000..bc200d0a1
--- /dev/null
+++ b/libchrome_tools/jni_registration_generator_helper.sh
@@ -0,0 +1,40 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# Generates jni.
+
+set -e
+
+args=()
+files=()
+
+jni_generator=''
+
+for arg in "$@"; do
+ case "${arg}" in
+ --jni_generator=*)
+ jni_generator=${arg#'--jni_generator='}
+ ;;
+ --*)
+ args=("${args[@]}" "${arg}")
+ ;;
+ *)
+ files=("${files[@]}" "${arg}")
+ ;;
+ esac
+done
+
+"${jni_generator}" --sources_files=<(printf "%q\n" "${files[@]}") "${args[@]}"
diff --git a/libchrome_tools/mojom_generate_type_mappings.py b/libchrome_tools/mojom_generate_type_mappings.py
new file mode 100755
index 000000000..a532e307f
--- /dev/null
+++ b/libchrome_tools/mojom_generate_type_mappings.py
@@ -0,0 +1,108 @@
+#!/usr/bin/python
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Drives mojom typemapping generator.
+
+Usage:
+
+% python libchrome_tools/mojom_generate_type_mappings.py \
+ --output ${output_type_mapping_file_path} \
+ ${list of .typemap files}
+"""
+
+import argparse
+import os
+import subprocess
+import sys
+
+
+try:
+ # ../build cannot be loaded if cwd is other directories
+ # e.g. when emerge libchrome
+ sys.path.append(os.path.join(os.path.dirname(sys.argv[0]), '..'))
+ from build import gn_helpers
+except ImportError:
+ # gn_helpers is located at the same directory when building other packages
+ # in system directory.
+ import gn_helpers
+
+# script in libchrome repositority is used when emerge libchrome.
+_GENERATE_TYPE_MAPPINGS_PATH = os.path.join(
+ os.path.dirname(__file__),
+ '../mojo/public/tools/bindings/generate_type_mappings.py')
+if not os.path.isfile(_GENERATE_TYPE_MAPPINGS_PATH):
+ # use system script in the same dir when building other packages.
+ _GENERATE_TYPE_MAPPINGS_PATH = os.path.join(
+ os.path.dirname(__file__),
+ 'generate_type_mappings.py')
+
+def _read_typemap_config(path):
+ """Reads .typemap file.
+
+ Args:
+ path: File path to the .typemap location.
+
+ Returns:
+ A dictionary holding values in .typemap file.
+ """
+
+ with open(path) as f:
+ # gn_helpers does not handle comment lines.
+ content = [line for line in f if not line.strip().startswith('#')]
+ return gn_helpers.FromGNArgs(''.join(content))
+
+
+def _generate_type_mappings(input_paths, output):
+ """Generates __type_mappings file from given .typemap files.
+
+ Builds a command line to run generate_type_mappings.py, and executes it.
+
+ Args:
+ input_paths: a list of file paths for .typemap files.
+ output: a path to output __type_mappings file.
+ """
+ command = [sys.executable, _GENERATE_TYPE_MAPPINGS_PATH, '--output', output]
+
+ # TODO(hidehiko): Add dependency handling.
+
+ for path in input_paths:
+ typemap_config = _read_typemap_config(path)
+ command.append('--start-typemap')
+ for public_header in typemap_config.get('public_headers', []):
+ command.append('public_headers=' + public_header)
+ for traits_header in typemap_config.get('traits_headers', []):
+ command.append('traits_headers=' + traits_header)
+ for type_mapping in typemap_config.get('type_mappings', []):
+ command.append('type_mappings=' + type_mapping)
+
+ subprocess.check_call(command)
+
+
+def _parse_args():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--output', help='Output file path')
+ parser.add_argument('input_paths', metavar="INPUT-PATH", nargs='+',
+ help='Input typemap files.')
+ return parser.parse_args()
+
+
+def main():
+ args = _parse_args()
+ _generate_type_mappings(args.input_paths, args.output)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/libchrome_tools/patch/0001-Use-qualified-base-make_optional-in-optional_unittes.patch b/libchrome_tools/patch/0001-Use-qualified-base-make_optional-in-optional_unittes.patch
new file mode 100644
index 000000000..f053d7557
--- /dev/null
+++ b/libchrome_tools/patch/0001-Use-qualified-base-make_optional-in-optional_unittes.patch
@@ -0,0 +1,102 @@
+From d2e73f1115bfed906f2a10dc69aebced6774bac3 Mon Sep 17 00:00:00 2001
+From: tzik <tzik@chromium.org>
+Date: Wed, 17 Oct 2018 12:38:46 +0000
+Subject: [PATCH] Use qualified base::make_optional in optional_unittest.cc
+
+Unqualified usage of make_optional causes a compile error if:
+ - It's compiler in C++17 mode and <optional> is included.
+ - The parameter of make_optional is in std namespace, such as
+ std::string.
+As std::make_optional is pulled by ADL rule and conflicts to
+base::make_optional in this situation.
+
+This CL replaces them with qualified base::make_optional, and
+replaces others for consistency.
+
+Change-Id: I2045e9eac0e4466dce266112eab5bf7c8555c2ef
+Reviewed-on: https://chromium-review.googlesource.com/c/1282512
+Reviewed-by: Daniel Cheng <dcheng@chromium.org>
+Reviewed-by: Hidehiko Abe <hidehiko@chromium.org>
+Commit-Queue: Taiju Tsuiki <tzik@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#600361}
+---
+ base/optional_unittest.cc | 25 +++++++++++++++----------
+ 1 file changed, 15 insertions(+), 10 deletions(-)
+
+diff --git a/base/optional_unittest.cc b/base/optional_unittest.cc
+index 7bdb46b76173..365e99da41df 100644
+--- a/base/optional_unittest.cc
++++ b/base/optional_unittest.cc
+@@ -1899,34 +1899,39 @@ TEST(OptionalTest, NotEqualsNull) {
+
+ TEST(OptionalTest, MakeOptional) {
+ {
+- Optional<float> o = make_optional(32.f);
++ // Use qualified base::make_optional here and elsewhere to avoid the name
++ // confliction to std::make_optional.
++ // The name conflict happens only for types in std namespace, such as
++ // std::string. The other qualified base::make_optional usages are just for
++ // consistency.
++ Optional<float> o = base::make_optional(32.f);
+ EXPECT_TRUE(o);
+ EXPECT_EQ(32.f, *o);
+
+ float value = 3.f;
+- o = make_optional(std::move(value));
++ o = base::make_optional(std::move(value));
+ EXPECT_TRUE(o);
+ EXPECT_EQ(3.f, *o);
+ }
+
+ {
+- Optional<std::string> o = make_optional(std::string("foo"));
++ Optional<std::string> o = base::make_optional(std::string("foo"));
+ EXPECT_TRUE(o);
+ EXPECT_EQ("foo", *o);
+
+ std::string value = "bar";
+- o = make_optional(std::move(value));
++ o = base::make_optional(std::move(value));
+ EXPECT_TRUE(o);
+ EXPECT_EQ(std::string("bar"), *o);
+ }
+
+ {
+- Optional<TestObject> o = make_optional(TestObject(3, 0.1));
++ Optional<TestObject> o = base::make_optional(TestObject(3, 0.1));
+ EXPECT_TRUE(!!o);
+ EXPECT_TRUE(TestObject(3, 0.1) == *o);
+
+ TestObject value = TestObject(0, 0.42);
+- o = make_optional(std::move(value));
++ o = base::make_optional(std::move(value));
+ EXPECT_TRUE(!!o);
+ EXPECT_TRUE(TestObject(0, 0.42) == *o);
+ EXPECT_EQ(TestObject::State::MOVED_FROM, value.state());
+@@ -1945,7 +1950,7 @@ TEST(OptionalTest, MakeOptional) {
+ bool c;
+ };
+
+- Optional<Test> o = make_optional<Test>(1, 2.0, true);
++ Optional<Test> o = base::make_optional<Test>(1, 2.0, true);
+ EXPECT_TRUE(!!o);
+ EXPECT_EQ(1, o->a);
+ EXPECT_EQ(2.0, o->b);
+@@ -1953,11 +1958,11 @@ TEST(OptionalTest, MakeOptional) {
+ }
+
+ {
+- auto str1 = make_optional<std::string>({'1', '2', '3'});
++ auto str1 = base::make_optional<std::string>({'1', '2', '3'});
+ EXPECT_EQ("123", *str1);
+
+- auto str2 =
+- make_optional<std::string>({'a', 'b', 'c'}, std::allocator<char>());
++ auto str2 = base::make_optional<std::string>({'a', 'b', 'c'},
++ std::allocator<char>());
+ EXPECT_EQ("abc", *str2);
+ }
+ }
+--
+2.20.0.405.gbc1bbc6f85-goog
+
diff --git a/libchrome_tools/patch/580fcef.patch b/libchrome_tools/patch/580fcef.patch
new file mode 100644
index 000000000..cff82bc63
--- /dev/null
+++ b/libchrome_tools/patch/580fcef.patch
@@ -0,0 +1,112 @@
+From 580fcef90ab970ad37ea9f7059373f773b3e55d2 Mon Sep 17 00:00:00 2001
+From: Jakub Pawlowski <jpawlowski@google.com>
+Date: Fri, 03 Aug 2018 08:46:10 +0000
+Subject: [PATCH] Fix data_types_definition.tmpl
+
+This template can generate code that does not compile, if there are
+multiple fields with different versions where at least one has version 0
+and end up being laid out in a way that does not match the ordinal order
+
+Sample Mojo file:
+// Describes ARC package.
+struct ArcPackageInfo {
+ string package_name;
+ int32 package_version;
+ int64 last_backup_android_id;
+ int64 last_backup_time;
+ bool sync; // true if package installation should be synced
+ [MinVersion=11] bool system; // true if package is system package.
+ // true if package registers VPNService intent.
+ [MinVersion=25] bool vpn_provider;
+};
+
+Sample badly generated code (no closing "}" for last if):
+
+ @SuppressWarnings("unchecked")
+ public static ArcPackageInfo decode(org.chromium.mojo.bindings.Decoder decoder0) {
+ if (decoder0 == null) {
+ return null;
+ }
+ decoder0.increaseStackDepth();
+ ArcPackageInfo result;
+ try {
+ org.chromium.mojo.bindings.DataHeader mainDataHeader = decoder0.readAndValidateDataHeader(VERSION_ARRAY);
+ final int elementsOrVersion = mainDataHeader.elementsOrVersion;
+ result = new ArcPackageInfo(elementsOrVersion);
+ {
+
+ result.packageName = decoder0.readString(8, false);
+ }
+ {
+
+ result.packageVersion = decoder0.readInt(16);
+ }
+ {
+
+ result.sync = decoder0.readBoolean(20, 0);
+ }
+ if (elementsOrVersion >= 11) {
+ {
+
+ result.system = decoder0.readBoolean(20, 1);
+ }
+ }
+ if (elementsOrVersion >= 25) {
+ {
+
+ result.vpnProvider = decoder0.readBoolean(20, 2);
+ }
+ }
+ if (elementsOrVersion >= 0) {
+ {
+
+ result.lastBackupAndroidId = decoder0.readLong(24);
+ }
+ {
+
+ result.lastBackupTime = decoder0.readLong(32);
+ }
+ } finally {
+ decoder0.decreaseStackDepth();
+ }
+ return result;
+ }
+
+Change-Id: I4c1b573a71b20cc6a0828a2cceff6bbfbb4ac5bc
+Reviewed-on: https://chromium-review.googlesource.com/1158702
+Reviewed-by: Luis Hector Chavez <lhchavez@chromium.org>
+Reviewed-by: Ken Rockot <rockot@chromium.org>
+Commit-Queue: Jakub x Jakub Pawlowski <jpawlowski@google.com>
+Cr-Commit-Position: refs/heads/master@{#580480}
+---
+
+diff --git a/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl b/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
+index 59c6fee..7af57bd 100644
+--- a/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
++++ b/mojo/public/tools/bindings/generators/java_templates/data_types_definition.tmpl
+@@ -175,6 +175,7 @@
+ org.chromium.mojo.bindings.DataHeader mainDataHeader = decoder0.readAndValidateDataHeader(VERSION_ARRAY);
+ final int elementsOrVersion = mainDataHeader.elementsOrVersion;
+ result = new {{struct|name}}(elementsOrVersion);
++
+ {%- set prev_ver = [0] %}
+ {%- for byte in struct.bytes %}
+ {%- for packed_field in byte.packed_fields %}
+@@ -183,7 +184,9 @@
+ }
+ {%- endif %}
+ {%- set _ = prev_ver.append(packed_field.min_version) %}
++{%- if prev_ver[-1] != 0 %}
+ if (elementsOrVersion >= {{packed_field.min_version}}) {
++{%- endif %}
+ {%- endif %}
+ {
+ {{decode('result.' ~ packed_field.field|name, packed_field.field.kind, 8+packed_field.offset, packed_field.bit)|indent(16)}}
+@@ -193,6 +196,7 @@
+ {%- if prev_ver[-1] != 0 %}
+ }
+ {%- endif %}
++
+ } finally {
+ decoder0.decreaseStackDepth();
+ }
diff --git a/libchrome_tools/patch/8fbafc9.patch b/libchrome_tools/patch/8fbafc9.patch
new file mode 100644
index 000000000..d872f9e79
--- /dev/null
+++ b/libchrome_tools/patch/8fbafc9.patch
@@ -0,0 +1,25 @@
+From 8fbafc974b92d26780d7e2a8c36856ff689e8f6b Mon Sep 17 00:00:00 2001
+From: Jakub Pawlowski <jpawlowski@google.com>
+Date: Thu, 27 Sep 2018 19:10:56 +0000
+Subject: [PATCH] Add missing include for condition variable in base/test/test_mock_time_task_runner.h
+
+Change-Id: Ia6b77632aab5df842c8878fba6fc96bf405a28de
+Reviewed-on: https://chromium-review.googlesource.com/1249488
+Reviewed-by: Luis Hector Chavez <lhchavez@chromium.org>
+Reviewed-by: Gabriel Charette <gab@chromium.org>
+Commit-Queue: Gabriel Charette <gab@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#594806}
+---
+
+diff --git a/base/test/test_mock_time_task_runner.h b/base/test/test_mock_time_task_runner.h
+index dd7274c..dcfbcbd 100644
+--- a/base/test/test_mock_time_task_runner.h
++++ b/base/test/test_mock_time_task_runner.h
+@@ -17,6 +17,7 @@
+ #include "base/macros.h"
+ #include "base/run_loop.h"
+ #include "base/single_thread_task_runner.h"
++#include "base/synchronization/condition_variable.h"
+ #include "base/synchronization/lock.h"
+ #include "base/test/test_pending_task.h"
+ #include "base/threading/thread_checker_impl.h"
diff --git a/libchrome_tools/patch/ContextUtils.patch b/libchrome_tools/patch/ContextUtils.patch
new file mode 100644
index 000000000..6e1a484f7
--- /dev/null
+++ b/libchrome_tools/patch/ContextUtils.patch
@@ -0,0 +1,18 @@
+diff --git a/base/android/java/src/org/chromium/base/ContextUtils.java b/base/android/java/src/org/chromium/base/ContextUtils.java
+index 8284cd1..c648e01 100644
+--- a/base/android/java/src/org/chromium/base/ContextUtils.java
++++ b/base/android/java/src/org/chromium/base/ContextUtils.java
+@@ -100,9 +100,10 @@ public class ContextUtils {
+ // that use Robolectric and set the application context manually. Instead of changing all
+ // tests that do so, the call was put here instead.
+ // TODO(mheikal): Require param to be of type Application
+- if (appContext instanceof Application) {
+- ApplicationStatus.initialize((Application) appContext);
+- }
++ // Disabled on libchrome
++ // if (appContext instanceof Application) {
++ // ApplicationStatus.initialize((Application) appContext);
++ // }
+ initJavaSideApplicationContext(appContext);
+ Holder.sSharedPreferences = fetchAppSharedPreferences();
+ }
diff --git a/libchrome_tools/patch/ThreadLocalStorage-Add-a-function-to-destroy-pthread.patch b/libchrome_tools/patch/ThreadLocalStorage-Add-a-function-to-destroy-pthread.patch
new file mode 100644
index 000000000..2c214379b
--- /dev/null
+++ b/libchrome_tools/patch/ThreadLocalStorage-Add-a-function-to-destroy-pthread.patch
@@ -0,0 +1,63 @@
+From 28a638ff22f598f6aa9388db6a4cf13fe9f11644 Mon Sep 17 00:00:00 2001
+From: Hirokazu Honda <hiroh@google.com>
+Date: Wed, 1 Aug 2018 17:03:18 +0900
+Subject: [PATCH] ThreadLocalStorage: Add a function to destroy pthread key
+ used in libchrome
+
+MojoProcessSupport needs to destroy pthread key which is globally used in libchrome. The key is
+stored in a local variable in thread_local_storage.cc.
+This adds a function to destroy the key so that MojoProcessSupport can do it.
+
+Bug: 110722333
+Test: No crash in opening DRMInfo.app
+Test: PlayStore still works
+Test: cheets_ContainerSmokeTest and cheets_LoginScreen
+Change-Id: Ib10c83deb5f7ef141d4ab9883e0d2c31d422a1b1
+---
+ base/threading/thread_local_storage.cc | 11 +++++++++++
+ base/threading/thread_local_storage.h | 7 +++++++
+ 2 files changed, 18 insertions(+)
+
+diff --git a/base/threading/thread_local_storage.cc b/base/threading/thread_local_storage.cc
+index 48c1dd5..90ae69e 100644
+--- a/base/threading/thread_local_storage.cc
++++ b/base/threading/thread_local_storage.cc
+@@ -247,6 +247,17 @@ void PlatformThreadLocalStorage::OnThreadExit() {
+ void PlatformThreadLocalStorage::OnThreadExit(void* value) {
+ OnThreadExitInternal(static_cast<TlsVectorEntry*>(value));
+ }
++
++// static
++void PlatformThreadLocalStorage::ForceFreeTLS() {
++ PlatformThreadLocalStorage::TLSKey key =
++ base::subtle::NoBarrier_AtomicExchange(
++ &g_native_tls_key,
++ PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES);
++ if (key == PlatformThreadLocalStorage::TLS_KEY_OUT_OF_INDEXES)
++ return;
++ PlatformThreadLocalStorage::FreeTLS(key);
++}
+ #endif // defined(OS_WIN)
+
+ } // namespace internal
+diff --git a/base/threading/thread_local_storage.h b/base/threading/thread_local_storage.h
+index fd2a789..c5c7759 100644
+--- a/base/threading/thread_local_storage.h
++++ b/base/threading/thread_local_storage.h
+@@ -75,6 +75,13 @@ class BASE_EXPORT PlatformThreadLocalStorage {
+ // GetTLSValue() to retrieve the value of slot as it has already been reset
+ // in Posix.
+ static void OnThreadExit(void* value);
++ // Normally, Chrome runs as a process, so freeing the TLS is not needed since
++ // the OS will perform that while it's reclaiming the process' memory upon
++ // termination. If, however, this code is used inside a library that is
++ // dynamically loaded and unloaded, the consumer is responsible for calling
++ // this after all Chrome threads have stopped and prior to unloading the
++ // library.
++ static void ForceFreeTLS();
+ #endif
+ };
+
+--
+2.18.0.345.g5c9ce644c3-goog
+
diff --git a/libchrome_tools/patch/alignof_int64.patch b/libchrome_tools/patch/alignof_int64.patch
new file mode 100644
index 000000000..121def4d3
--- /dev/null
+++ b/libchrome_tools/patch/alignof_int64.patch
@@ -0,0 +1,88 @@
+From 5177b28400e03d8666dfb3e65c3016b5062ce0f7 Mon Sep 17 00:00:00 2001
+From: Chih-Hung Hsieh <chh@google.com>
+Date: Thu, 15 Nov 2018 16:07:02 -0800
+Subject: [PATCH] Update asserts in mojo about int64_t's alignment
+
+The purpose of these asserts is to check that the options structs are aligned
+sufficiently that an int64_t (or similar) could be added to them. The asserts
+were added in https://codereview.chromium.org/295383012
+
+However, the alignment of int64_t on 32-bit x86 is actually 4 bytes, not 8. So
+how did this ever work? Before Clang r345419, the alignof() operator (which is what
+MOJO_ALIGNOF maps to) would return the *preferred alignment* of a type, not
+the *ABI alignment*. That's not what the C and C++ standards specify, so the
+bug was fixed and the asserts started firing. (See also
+https://llvm.org/pr26547)
+
+To fix the build, change the asserts to check that int64_t requires 8 bytes
+alignment *or less*.
+
+Bug: 900406
+Bug: 119634736
+Change-Id: Icf80cea80ac31082423faab8c192420d0b98d515
+Reviewed-on: https://chromium-review.googlesource.com/c/1318971
+Commit-Queue: Ken Rockot <rockot@google.com>
+Reviewed-by: Ken Rockot <rockot@google.com>
+Cr-Commit-Position: refs/heads/master@{#605699}
+---
+ mojo/core/options_validation_unittest.cc | 2 +-
+ mojo/public/c/system/buffer.h | 2 +-
+ mojo/public/c/system/data_pipe.h | 2 +-
+ mojo/public/c/system/message_pipe.h | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/mojo/core/options_validation_unittest.cc b/mojo/core/options_validation_unittest.cc
+index 52e0032..b4b02dc 100644
+--- a/mojo/core/options_validation_unittest.cc
++++ b/mojo/core/options_validation_unittest.cc
+@@ -18,7 +18,7 @@ namespace {
+
+ using TestOptionsFlags = uint32_t;
+
+-static_assert(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
++static_assert(MOJO_ALIGNOF(int64_t) <= 8, "int64_t has weird alignment");
+ struct MOJO_ALIGNAS(8) TestOptions {
+ uint32_t struct_size;
+ TestOptionsFlags flags;
+diff --git a/mojo/public/c/system/buffer.h b/mojo/public/c/system/buffer.h
+index 2cc5427..83b198b 100644
+--- a/mojo/public/c/system/buffer.h
++++ b/mojo/public/c/system/buffer.h
+@@ -30,7 +30,7 @@ struct MOJO_ALIGNAS(8) MojoCreateSharedBufferOptions {
+ // See |MojoCreateSharedBufferFlags|.
+ MojoCreateSharedBufferFlags flags;
+ };
+-MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
++MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) <= 8, "int64_t has weird alignment");
+ MOJO_STATIC_ASSERT(sizeof(MojoCreateSharedBufferOptions) == 8,
+ "MojoCreateSharedBufferOptions has wrong size");
+
+diff --git a/mojo/public/c/system/data_pipe.h b/mojo/public/c/system/data_pipe.h
+index 3702cdb..c72f553 100644
+--- a/mojo/public/c/system/data_pipe.h
++++ b/mojo/public/c/system/data_pipe.h
+@@ -40,7 +40,7 @@ struct MOJO_ALIGNAS(8) MojoCreateDataPipeOptions {
+ // system-dependent capacity of at least one element in size.
+ uint32_t capacity_num_bytes;
+ };
+-MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
++MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) <= 8, "int64_t has weird alignment");
+ MOJO_STATIC_ASSERT(sizeof(MojoCreateDataPipeOptions) == 16,
+ "MojoCreateDataPipeOptions has wrong size");
+
+diff --git a/mojo/public/c/system/message_pipe.h b/mojo/public/c/system/message_pipe.h
+index 9f222f9..0f642dd 100644
+--- a/mojo/public/c/system/message_pipe.h
++++ b/mojo/public/c/system/message_pipe.h
+@@ -35,7 +35,7 @@ struct MOJO_ALIGNAS(8) MojoCreateMessagePipeOptions {
+ // See |MojoCreateMessagePipeFlags|.
+ MojoCreateMessagePipeFlags flags;
+ };
+-MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) == 8, "int64_t has weird alignment");
++MOJO_STATIC_ASSERT(MOJO_ALIGNOF(int64_t) <= 8, "int64_t has weird alignment");
+ MOJO_STATIC_ASSERT(sizeof(MojoCreateMessagePipeOptions) == 8,
+ "MojoCreateMessagePipeOptions has wrong size");
+
+--
+2.20.0.rc0.387.gc7a69e6b6c-goog
+
diff --git a/libchrome_tools/patch/allocator_shim.patch b/libchrome_tools/patch/allocator_shim.patch
new file mode 100644
index 000000000..f5fe9e801
--- /dev/null
+++ b/libchrome_tools/patch/allocator_shim.patch
@@ -0,0 +1,13 @@
+# Use allocator_shim_override_linker_wrapped_symbols.h for ANDROID.
+
+--- a/base/allocator/allocator_shim.cc
++++ b/base/allocator/allocator_shim.cc
+@@ -285,7 +285,7 @@ ALWAYS_INLINE void ShimFreeDefiniteSize(void* ptr, size_t size, void* context) {
+ #include "base/allocator/allocator_shim_override_cpp_symbols.h"
+ #endif
+
+-#if defined(OS_ANDROID)
++#if defined(OS_ANDROID) || defined(ANDROID)
+ // Android does not support symbol interposition. The way malloc symbols are
+ // intercepted on Android is by using link-time -wrap flags.
+ #include "base/allocator/allocator_shim_override_linker_wrapped_symbols.h"
diff --git a/libchrome_tools/patch/ashmem.patch b/libchrome_tools/patch/ashmem.patch
new file mode 100644
index 000000000..c59a53677
--- /dev/null
+++ b/libchrome_tools/patch/ashmem.patch
@@ -0,0 +1,20 @@
+--- /dev/null
++++ b/third_party/ashmem/ashmem.h
+@@ -0,0 +1,17 @@
++// Copyright (C) 2018 The Android Open Source Project
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++
++// third_party/ashmem is Android shared memory. Instead of clone it here,
++// use cutils/ashmem.h directly.
++#include <cutils/ashmem.h>
diff --git a/libchrome_tools/patch/build_config.patch b/libchrome_tools/patch/build_config.patch
new file mode 100644
index 000000000..daf5fb27e
--- /dev/null
+++ b/libchrome_tools/patch/build_config.patch
@@ -0,0 +1,53 @@
+--- a/build/build_config.h
++++ b/build/build_config.h
+@@ -16,6 +16,40 @@
+ #ifndef BUILD_BUILD_CONFIG_H_
+ #define BUILD_BUILD_CONFIG_H_
+
++// A brief primer on #defines:
++//
++// - __ANDROID__ is automatically defined by the Android toolchain (see
++// https://goo.gl/v61lXa). It's not defined when building host code.
++// - __ANDROID_HOST__ is defined via -D by Android.mk when building host code
++// within an Android checkout.
++// - ANDROID is defined via -D when building code for either Android targets or
++// hosts. Use __ANDROID__ and __ANDROID_HOST__ instead.
++// - OS_ANDROID is a Chrome-specific define used to build Chrome for Android
++// within the NDK.
++
++// Android targets and hosts don't use tcmalloc.
++#if defined(__ANDROID__) || defined(__ANDROID_HOST__)
++#define NO_TCMALLOC
++#endif // defined(__ANDROID__) || defined(__ANDROID_HOST__)
++
++// Use the Chrome OS version of the code for both Android targets and Chrome OS builds.
++#if !defined(__ANDROID_HOST__)
++#define OS_CHROMEOS 1
++#endif // !defined(__ANDROID_HOST__)
++
++#if defined(__ANDROID__) // Android targets
++
++#define __linux__ 1
++
++#elif !defined(__ANDROID_HOST__) // Chrome OS
++
++// TODO: Remove these once the GLib MessageLoopForUI isn't being used:
++// https://crbug.com/361635
++#define USE_GLIB 1
++#define USE_OZONE 1
++
++#endif // defined(__ANDROID__)
++
+ // A set of macros to use for platform detection.
+ #if defined(__native_client__)
+ // __native_client__ must be first, so that other OS_ defines are not set.
+@@ -28,8 +62,7 @@
+ #else
+ #define OS_NACL_SFI
+ #endif
+-#elif defined(ANDROID)
+-#define OS_ANDROID 1
++// Don't set OS_ANDROID; it's only used when building Chrome for Android.
+ #elif defined(__APPLE__)
+ // only include TargetConditions after testing ANDROID as some android builds
+ // on mac don't have this header available and it's not needed unless the target
diff --git a/libchrome_tools/patch/build_time.patch b/libchrome_tools/patch/build_time.patch
new file mode 100644
index 000000000..cebe8a6f1
--- /dev/null
+++ b/libchrome_tools/patch/build_time.patch
@@ -0,0 +1,74 @@
+--- a/base/build_time.cc
++++ b/base/build_time.cc
+@@ -4,20 +4,31 @@
+
+ #include "base/build_time.h"
+
+-// Imports the generated build date, i.e. BUILD_DATE.
+-#include "base/generated_build_date.h"
+-
+ #include "base/logging.h"
+ #include "base/time/time.h"
+
++#ifdef __ANDROID__
++#include <cutils/properties.h>
++#endif
++
+ namespace base {
+
+ Time GetBuildTime() {
+ Time integral_build_time;
+- // BUILD_DATE is exactly "Mmm DD YYYY HH:MM:SS".
+- // See //build/write_build_date_header.py. "HH:MM:SS" is normally expected to
+- // be "05:00:00" but is not enforced here.
+- bool result = Time::FromUTCString(BUILD_DATE, &integral_build_time);
++ // The format of __DATE__ and __TIME__ is specified by the ANSI C Standard,
++ // section 6.8.8.
++ //
++ // __DATE__ is exactly "Mmm DD YYYY".
++ // __TIME__ is exactly "hh:mm:ss".
++#if defined(__ANDROID__)
++ char kDateTime[PROPERTY_VALUE_MAX];
++ property_get("ro.build.date", kDateTime, "Sep 02 2008 08:00:00 PST");
++#elif defined(DONT_EMBED_BUILD_METADATA) && !defined(OFFICIAL_BUILD)
++ const char kDateTime[] = "Sep 02 2008 08:00:00 PST";
++#else
++ const char kDateTime[] = __DATE__ " " __TIME__ " PST";
++#endif
++ bool result = Time::FromString(kDateTime, &integral_build_time);
+ DCHECK(result);
+ return integral_build_time;
+ }
+--- a/base/build_time_unittest.cc
++++ b/base/build_time_unittest.cc
+@@ -3,13 +3,19 @@
+ // found in the LICENSE file.
+
+ #include "base/build_time.h"
++#if !defined(DONT_EMBED_BUILD_METADATA)
+ #include "base/generated_build_date.h"
++#endif
+ #include "base/time/time.h"
+
+ #include "testing/gtest/include/gtest/gtest.h"
+
+ TEST(BuildTime, DateLooksValid) {
++#if !defined(DONT_EMBED_BUILD_METADATA)
+ char build_date[] = BUILD_DATE;
++#else
++ char build_date[] = "Sep 02 2008 05:00:00";
++#endif
+
+ EXPECT_EQ(20u, strlen(build_date));
+ EXPECT_EQ(' ', build_date[3]);
+@@ -30,8 +36,10 @@ TEST(BuildTime, InThePast) {
+ EXPECT_LT(base::GetBuildTime(), base::Time::NowFromSystemTime());
+ }
+
++#if !defined(DONT_EMBED_BUILD_METADATA)
+ TEST(BuildTime, NotTooFar) {
+ // BuildTime must be less than 45 days old.
+ base::Time cutoff(base::Time::Now() - base::TimeDelta::FromDays(45));
+ EXPECT_GT(base::GetBuildTime(), cutoff);
+ }
++#endif
diff --git a/libchrome_tools/patch/buildflag_header.patch b/libchrome_tools/patch/buildflag_header.patch
new file mode 100644
index 000000000..55abdc044
--- /dev/null
+++ b/libchrome_tools/patch/buildflag_header.patch
@@ -0,0 +1,97 @@
+# These files are generated by buildflag_header rule in Chromium.
+# Instead, in libchrome, these are checked in.
+
+--- /dev/null
++++ b/base/allocator/buildflags.h
+@@ -0,0 +1,5 @@
++#ifndef BASE_ALLOCATOR_BUILDFLAGS_H_
++#define BASE_ALLOCATOR_BUILDFLAGS_H_
++#include "build/buildflag.h"
++#define BUILDFLAG_INTERNAL_USE_ALLOCATOR_SHIM() (0)
++#endif // BASE_ALLOCATOR_BUILDFLAGS_H_
+--- /dev/null
++++ b/base/android/java/src/org/chromium/base/BuildConfig.java
+@@ -0,0 +1,21 @@
++// Copyright 2015 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++package org.chromium.base;
++
++/**
++ * Build configuration. Generated on a per-target basis.
++ */
++public class BuildConfig {
++
++
++ public static final String FIREBASE_APP_ID = "";
++
++ public static final boolean DCHECK_IS_ON = false;
++
++ // The ID of the android string resource that stores the product version.
++ // This layer of indirection is necessary to make the resource dependency
++ // optional for android_apk targets/base_java (ex. for cronet).
++ public static final int R_STRING_PRODUCT_VERSION = 0;
++}
+--- /dev/null
++++ b/base/cfi_buildflags.h
+@@ -0,0 +1,7 @@
++// Generated by build/write_buildflag_header.py
++// From "base_debugging_flags"
++#ifndef BASE_CFI_BUILDFLAGS_H_
++#define BASE_CFI_BUILDFLAGS_H_
++#include "build/buildflag.h"
++#define BUILDFLAG_INTERNAL_CFI_ICALL_CHECK() (0)
++#endif // BASE_CFI_BUILDFLAGS_H_
+--- /dev/null
++++ b/base/debug/debugging_buildflags.h
+@@ -0,0 +1,12 @@
++// Generated by build/write_buildflag_header.py
++// From "base_debugging_flags"
++#ifndef BASE_DEBUG_DEBUGGING_FLAGS_H_
++#define BASE_DEBUG_DEBUGGING_FLAGS_H_
++#include "build/buildflag.h"
++#define BUILDFLAG_INTERNAL_ENABLE_PROFILING() (0)
++#define BUILDFLAG_INTERNAL_ENABLE_MEMORY_TASK_PROFILER() (0)
++#define BUILDFLAG_INTERNAL_CAN_UNWIND_WITH_FRAME_POINTERS() (0)
++#define BUILDFLAG_INTERNAL_ENABLE_LOCATION_SOURCE() (0)
++#define BUILDFLAG_INTERNAL_CFI_ENFORCEMENT_TRAP() (0)
++#define BUILDFLAG_INTERNAL_ENABLE_MUTEX_PRIORITY_INHERITANCE() (0)
++#endif // BASE_DEBUG_DEBUGGING_FLAGS_H_
+--- /dev/null
++++ b/base/memory/protected_memory_buildflags.h
+@@ -0,0 +1,7 @@
++// Generated by build/write_buildflag_header.py
++// From "base_debugging_flags"
++#ifndef BASE_PROTECTED_MEMORY_BUILDFLAGS_H_
++#define BASE_PROTECTED_MEMORY_BUILDFLAGS_H_
++#include "build/buildflag.h"
++#define BUILDFLAG_INTERNAL_USE_LLD() (0)
++#endif // BASE_PROTECTED_MEMORY_BUILDFLAGS_H_
+--- /dev/null
++++ b/base/synchronization/synchronization_buildflags.h
+@@ -0,0 +1,4 @@
++#ifndef BASE_SYNCHRONIZATION_BUILDFLAGS_H_
++#define BASE_SYNCHRONIZATION_BUILDFLAGS_H_
++#include "build/buildflag.h"
++#endif // BASE_SYNCHRONIZATION_BUILDFLAGS_H_
+--- /dev/null
++++ b/ipc/ipc_buildflags.h
+@@ -0,0 +1,8 @@
++#ifndef CPP_IPC_BUILDFLAGS_H_
++#define CPP_IPC_BUILDFLAGS_H_
++
++#include <build/buildflag.h>
++
++#define BUILDFLAG_INTERNAL_IPC_MESSAGE_LOG_ENABLED() (0)
++
++#endif // CPP_IPC_BUILDFLAGS_H_
+--- /dev/null
++++ b/mojo/public/cpp/bindings/mojo_buildflags.h
+@@ -0,0 +1,6 @@
++#ifndef CPP_MOJO_BUILD_FLAGS_H_
++#define CPP_MOJO_BUILD_FLAGS_H_
++
++#include <build/buildflag.h>
++#define BUILDFLAG_INTERNAL_MOJO_TRACE_ENABLED() (0)
++#endif // CPP_MOJO_BUILD_FLAGS_H_
diff --git a/libchrome_tools/patch/c7ce19d.patch b/libchrome_tools/patch/c7ce19d.patch
new file mode 100644
index 000000000..1d6b9d968
--- /dev/null
+++ b/libchrome_tools/patch/c7ce19d.patch
@@ -0,0 +1,28 @@
+From c7ce19d52a7e6f3e69e66107650992765da559b7 Mon Sep 17 00:00:00 2001
+From: Jakub Pawlowski <jpawlowski@google.com>
+Date: Mon, 06 Aug 2018 03:06:46 +0000
+Subject: [PATCH] Make LAZY_INSTANCE_INITIALIZER -Wmissing-field-initializers friendly
+
+If libbase is compiled with -Wmissing-field-initializers this is causing
+warning to be generated.
+
+Change-Id: I446160d4c94bb59dd23f2f151004a8bfaeae832d
+Reviewed-on: https://chromium-review.googlesource.com/1161927
+Reviewed-by: Gabriel Charette <gab@chromium.org>
+Commit-Queue: Luis Hector Chavez <lhchavez@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#580794}
+---
+
+diff --git a/base/lazy_instance.h b/base/lazy_instance.h
+index 36d3158..4449373 100644
+--- a/base/lazy_instance.h
++++ b/base/lazy_instance.h
+@@ -55,7 +55,7 @@
+
+ // LazyInstance uses its own struct initializer-list style static
+ // initialization, which does not require a constructor.
+-#define LAZY_INSTANCE_INITIALIZER {0}
++#define LAZY_INSTANCE_INITIALIZER {}
+
+ namespace base {
+
diff --git a/libchrome_tools/patch/compiler_specific.patch b/libchrome_tools/patch/compiler_specific.patch
new file mode 100644
index 000000000..87d7354c0
--- /dev/null
+++ b/libchrome_tools/patch/compiler_specific.patch
@@ -0,0 +1,16 @@
+# In Android, prefer Android's libbase definitions for LIKELY/UNLIKELY macros.
+
+--- a/base/compiler_specific.h
++++ b/base/compiler_specific.h
+@@ -7,6 +7,11 @@
+
+ #include "build/build_config.h"
+
++#if defined(ANDROID)
++// Prefer Android's libbase definitions to our own.
++#include <android-base/macros.h>
++#endif // defined(ANDROID)
++
+ #if defined(COMPILER_MSVC)
+
+ // For _Printf_format_string_.
diff --git a/libchrome_tools/patch/dmg_fp.patch b/libchrome_tools/patch/dmg_fp.patch
new file mode 100644
index 000000000..95cc67d00
--- /dev/null
+++ b/libchrome_tools/patch/dmg_fp.patch
@@ -0,0 +1,160 @@
+# Libchrome does not support/require dmg_fp library. Instead, use standard
+# library.
+
+--- a/base/strings/string_number_conversions.cc
++++ b/base/strings/string_number_conversions.cc
+@@ -16,7 +16,6 @@
+ #include "base/numerics/safe_math.h"
+ #include "base/scoped_clear_errno.h"
+ #include "base/strings/utf_string_conversions.h"
+-#include "base/third_party/dmg_fp/dmg_fp.h"
+
+ namespace base {
+
+@@ -361,20 +360,35 @@ string16 NumberToString16(unsigned long long value) {
+ }
+
+ std::string NumberToString(double value) {
+- // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+- char buffer[32];
+- dmg_fp::g_fmt(buffer, value);
+- return std::string(buffer);
++ auto ret = std::to_string(value);
++ // If this returned an integer, don't do anything.
++ if (ret.find('.') == std::string::npos) {
++ return ret;
++ }
++ // Otherwise, it has an annoying tendency to leave trailing zeros.
++ size_t len = ret.size();
++ while (len >= 2 && ret[len - 1] == '0' && ret[len - 2] != '.') {
++ --len;
++ }
++ ret.erase(len);
++ return ret;
+ }
+
+ base::string16 NumberToString16(double value) {
+- // According to g_fmt.cc, it is sufficient to declare a buffer of size 32.
+- char buffer[32];
+- dmg_fp::g_fmt(buffer, value);
++ auto tmp = std::to_string(value);
++ base::string16 ret(tmp.c_str(), tmp.c_str() + tmp.length());
+
+- // The number will be ASCII. This creates the string using the "input
+- // iterator" variant which promotes from 8-bit to 16-bit via "=".
+- return base::string16(&buffer[0], &buffer[strlen(buffer)]);
++ // If this returned an integer, don't do anything.
++ if (ret.find('.') == std::string::npos) {
++ return ret;
++ }
++ // Otherwise, it has an annoying tendency to leave trailing zeros.
++ size_t len = ret.size();
++ while (len >= 2 && ret[len - 1] == '0' && ret[len - 2] != '.') {
++ --len;
++ }
++ ret.erase(len);
++ return ret;
+ }
+
+ bool StringToInt(StringPiece input, int* output) {
+@@ -418,14 +432,10 @@ bool StringToSizeT(StringPiece16 input, size_t* output) {
+ }
+
+ bool StringToDouble(const std::string& input, double* output) {
+- // Thread-safe? It is on at least Mac, Linux, and Windows.
+- ScopedClearErrno clear_errno;
+-
+ char* endptr = nullptr;
+- *output = dmg_fp::strtod(input.c_str(), &endptr);
++ *output = strtod(input.c_str(), &endptr);
+
+ // Cases to return false:
+- // - If errno is ERANGE, there was an overflow or underflow.
+ // - If the input string is empty, there was nothing to parse.
+ // - If endptr does not point to the end of the string, there are either
+ // characters remaining in the string after a parsed number, or the string
+@@ -433,10 +443,11 @@ bool StringToDouble(const std::string& input, double* output) {
+ // expected end given the string's stated length to correctly catch cases
+ // where the string contains embedded NUL characters.
+ // - If the first character is a space, there was leading whitespace
+- return errno == 0 &&
+- !input.empty() &&
++ return !input.empty() &&
+ input.c_str() + input.length() == endptr &&
+- !isspace(input[0]);
++ !isspace(input[0]) &&
++ *output != std::numeric_limits<double>::infinity() &&
++ *output != -std::numeric_limits<double>::infinity();
+ }
+
+ // Note: if you need to add String16ToDouble, first ask yourself if it's
+--- a/base/strings/string_number_conversions_unittest.cc
++++ b/base/strings/string_number_conversions_unittest.cc
+@@ -754,20 +754,8 @@ TEST(StringNumberConversionsTest, StringToDouble) {
+ {"9e999", HUGE_VAL, false},
+ {"9e1999", HUGE_VAL, false},
+ {"9e19999", HUGE_VAL, false},
+- {"9e99999999999999999999", HUGE_VAL, false},
+- {"-9e307", -9e307, true},
+- {"-1.7976e308", -1.7976e308, true},
+- {"-1.7977e308", -HUGE_VAL, false},
+- {"-1.797693134862315807e+308", -HUGE_VAL, true},
+- {"-1.797693134862315808e+308", -HUGE_VAL, false},
+- {"-9e308", -HUGE_VAL, false},
+- {"-9e309", -HUGE_VAL, false},
+- {"-9e999", -HUGE_VAL, false},
+- {"-9e1999", -HUGE_VAL, false},
+- {"-9e19999", -HUGE_VAL, false},
+- {"-9e99999999999999999999", -HUGE_VAL, false},
+-
+- // Test more exponents.
++ {"9e99999999999999999999", std::numeric_limits<double>::infinity(), false},
++ {"-9e99999999999999999999", -std::numeric_limits<double>::infinity(), false},
+ {"1e-2", 0.01, true},
+ {"42 ", 42.0, false},
+ {" 1e-2", 0.01, false},
+@@ -797,7 +785,8 @@ TEST(StringNumberConversionsTest, StringToDouble) {
+ for (size_t i = 0; i < arraysize(cases); ++i) {
+ double output;
+ errno = 1;
+- EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output));
++ EXPECT_EQ(cases[i].success, StringToDouble(cases[i].input, &output))
++ << "for input=" << cases[i].input << "got output=" << output;
+ if (cases[i].success)
+ EXPECT_EQ(1, errno) << i; // confirm that errno is unchanged.
+ EXPECT_DOUBLE_EQ(cases[i].output, output);
+@@ -818,13 +807,13 @@ TEST(StringNumberConversionsTest, DoubleToString) {
+ double input;
+ const char* expected;
+ } cases[] = {
+- {0.0, "0"},
++ {0.0, "0.0"},
+ {1.25, "1.25"},
+- {1.33518e+012, "1.33518e+12"},
+- {1.33489e+012, "1.33489e+12"},
+- {1.33505e+012, "1.33505e+12"},
+- {1.33545e+009, "1335450000"},
+- {1.33503e+009, "1335030000"},
++ {1.33518e+012, "1335180000000.0"},
++ {1.33489e+012, "1334890000000.0"},
++ {1.33505e+012, "1335050000000.0"},
++ {1.33545e+009, "1335450000.0"},
++ {1.33503e+009, "1335030000.0"},
+ };
+
+ for (size_t i = 0; i < arraysize(cases); ++i) {
+@@ -836,12 +825,12 @@ TEST(StringNumberConversionsTest, DoubleToString) {
+ const char input_bytes[8] = {0, 0, 0, 0, '\xee', '\x6d', '\x73', '\x42'};
+ double input = 0;
+ memcpy(&input, input_bytes, arraysize(input_bytes));
+- EXPECT_EQ("1335179083776", NumberToString(input));
++ EXPECT_EQ("1335179083776.0", NumberToString(input));
+ const char input_bytes2[8] =
+ {0, 0, 0, '\xa0', '\xda', '\x6c', '\x73', '\x42'};
+ input = 0;
+ memcpy(&input, input_bytes2, arraysize(input_bytes2));
+- EXPECT_EQ("1334890332160", NumberToString(input));
++ EXPECT_EQ("1334890332160.0", NumberToString(input));
+ }
+
+ TEST(StringNumberConversionsTest, HexEncode) {
diff --git a/libchrome_tools/patch/file_path_mojom.patch b/libchrome_tools/patch/file_path_mojom.patch
new file mode 100644
index 000000000..b61d62649
--- /dev/null
+++ b/libchrome_tools/patch/file_path_mojom.patch
@@ -0,0 +1,19 @@
+diff --git a/mojo/public/mojom/base/file_path.mojom b/mojo/public/mojom/base/file_path.mojom
+index 674d8cd..097b37e 100644
+--- a/mojo/public/mojom/base/file_path.mojom
++++ b/mojo/public/mojom/base/file_path.mojom
+@@ -5,7 +5,13 @@
+ module mojo_base.mojom;
+
+ struct FilePath {
+- [EnableIf=file_path_is_string]
++ // In chrome, ninja have a goal that can define file_path_is_string for a set
++ // of mojom files.
++ // In android we don't have such ability ,one would have to add
++ // "--enable_feature file_path_is_string" to all targets generating pickle
++ // files, headers and sources, and also in all project including them.
++ // Faster solution was to just remove this "EnableIf" definition in libchrome.
++ // [EnableIf=file_path_is_string]
+ string path;
+
+ // This duplicates the contents of mojo_base.mojom.String16. String16 isn't
diff --git a/libchrome_tools/patch/file_posix.patch b/libchrome_tools/patch/file_posix.patch
new file mode 100644
index 000000000..6fe3af80c
--- /dev/null
+++ b/libchrome_tools/patch/file_posix.patch
@@ -0,0 +1,24 @@
+# On Android, lseek64 should be used, whlie lseek should be in other platfrom.
+
+--- a/base/files/file_posix.cc
++++ b/base/files/file_posix.cc
+@@ -189,7 +189,9 @@ int64_t File::Seek(Whence whence, int64_t offset) {
+
+ SCOPED_FILE_TRACE_WITH_SIZE("Seek", offset);
+
+-#if defined(OS_ANDROID)
++// Additionally check __BIONIC__ since older versions of Android don't define
++// _FILE_OFFSET_BITS.
++#if _FILE_OFFSET_BITS != 64 || defined(__BIONIC__)
+ static_assert(sizeof(int64_t) == sizeof(off64_t), "off64_t must be 64 bits");
+ return lseek64(file_.get(), static_cast<off64_t>(offset),
+ static_cast<int>(whence));
+@@ -275,7 +277,7 @@ int File::Write(int64_t offset, const char* data, int size) {
+ int bytes_written = 0;
+ int rv;
+ do {
+-#if defined(OS_ANDROID)
++#if _FILE_OFFSET_BITS != 64 || defined(__BIONIC__)
+ // In case __USE_FILE_OFFSET64 is not used, we need to call pwrite64()
+ // instead of pwrite().
+ static_assert(sizeof(int64_t) == sizeof(off64_t), \ No newline at end of file
diff --git a/libchrome_tools/patch/gmock.patch b/libchrome_tools/patch/gmock.patch
new file mode 100644
index 000000000..a38afdce2
--- /dev/null
+++ b/libchrome_tools/patch/gmock.patch
@@ -0,0 +1,6 @@
+# Use system installed gmock library.
+
+--- /dev/null
++++ b/testing/gmock/include/gmock/gmock.h
+@@ -0,0 +1 @@
++#include <gmock/gmock.h>
diff --git a/libchrome_tools/patch/gtest.patch b/libchrome_tools/patch/gtest.patch
new file mode 100644
index 000000000..6da17c92e
--- /dev/null
+++ b/libchrome_tools/patch/gtest.patch
@@ -0,0 +1,10 @@
+# Use system installed gtest library.
+
+--- /dev/null
++++ b/testing/gtest/include/gtest/gtest.h
+@@ -0,0 +1 @@
++#include <gtest/gtest.h>
+--- /dev/null
++++ b/testing/gtest/include/gtest/gtest_prod.h
+@@ -0,0 +1 @@
++#include <gtest/gtest_prod.h>
diff --git a/libchrome_tools/patch/handle_table.patch b/libchrome_tools/patch/handle_table.patch
new file mode 100644
index 000000000..354fac81d
--- /dev/null
+++ b/libchrome_tools/patch/handle_table.patch
@@ -0,0 +1,176 @@
+diff --git a/mojo/core/handle_table.cc b/mojo/core/handle_table.cc
+index 62419a9..e039c71 100644
+--- a/mojo/core/handle_table.cc
++++ b/mojo/core/handle_table.cc
+@@ -8,35 +8,35 @@
+
+ #include <limits>
+
+-#include "base/trace_event/memory_dump_manager.h"
++// #include "base/trace_event/memory_dump_manager.h"
+
+ namespace mojo {
+ namespace core {
+
+ namespace {
+
+-const char* GetNameForDispatcherType(Dispatcher::Type type) {
+- switch (type) {
+- case Dispatcher::Type::UNKNOWN:
+- return "unknown";
+- case Dispatcher::Type::MESSAGE_PIPE:
+- return "message_pipe";
+- case Dispatcher::Type::DATA_PIPE_PRODUCER:
+- return "data_pipe_producer";
+- case Dispatcher::Type::DATA_PIPE_CONSUMER:
+- return "data_pipe_consumer";
+- case Dispatcher::Type::SHARED_BUFFER:
+- return "shared_buffer";
+- case Dispatcher::Type::WATCHER:
+- return "watcher";
+- case Dispatcher::Type::PLATFORM_HANDLE:
+- return "platform_handle";
+- case Dispatcher::Type::INVITATION:
+- return "invitation";
+- }
+- NOTREACHED();
+- return "unknown";
+-}
++// const char* GetNameForDispatcherType(Dispatcher::Type type) {
++// switch (type) {
++// case Dispatcher::Type::UNKNOWN:
++// return "unknown";
++// case Dispatcher::Type::MESSAGE_PIPE:
++// return "message_pipe";
++// case Dispatcher::Type::DATA_PIPE_PRODUCER:
++// return "data_pipe_producer";
++// case Dispatcher::Type::DATA_PIPE_CONSUMER:
++// return "data_pipe_consumer";
++// case Dispatcher::Type::SHARED_BUFFER:
++// return "shared_buffer";
++// case Dispatcher::Type::WATCHER:
++// return "watcher";
++// case Dispatcher::Type::PLATFORM_HANDLE:
++// return "platform_handle";
++// case Dispatcher::Type::INVITATION:
++// return "invitation";
++// }
++// NOTREACHED();
++// return "unknown";
++// }
+
+ } // namespace
+
+@@ -158,38 +158,38 @@ void HandleTable::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) {
+ }
+
+ // MemoryDumpProvider implementation.
+-bool HandleTable::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+- base::trace_event::ProcessMemoryDump* pmd) {
+- // Create entries for all relevant dispatcher types to ensure they are present
+- // in the final dump.
+- std::map<Dispatcher::Type, int> handle_count;
+- handle_count[Dispatcher::Type::MESSAGE_PIPE];
+- handle_count[Dispatcher::Type::DATA_PIPE_PRODUCER];
+- handle_count[Dispatcher::Type::DATA_PIPE_CONSUMER];
+- handle_count[Dispatcher::Type::SHARED_BUFFER];
+- handle_count[Dispatcher::Type::WATCHER];
+- handle_count[Dispatcher::Type::PLATFORM_HANDLE];
+- handle_count[Dispatcher::Type::INVITATION];
+-
+- // Count the number of each dispatcher type.
+- {
+- base::AutoLock lock(GetLock());
+- for (const auto& entry : handles_) {
+- ++handle_count[entry.second.dispatcher->GetType()];
+- }
+- }
+-
+- for (const auto& entry : handle_count) {
+- base::trace_event::MemoryAllocatorDump* inner_dump =
+- pmd->CreateAllocatorDump(std::string("mojo/") +
+- GetNameForDispatcherType(entry.first));
+- inner_dump->AddScalar(
+- base::trace_event::MemoryAllocatorDump::kNameObjectCount,
+- base::trace_event::MemoryAllocatorDump::kUnitsObjects, entry.second);
+- }
+-
+- return true;
+-}
++// bool HandleTable::OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
++// base::trace_event::ProcessMemoryDump* pmd) {
++// // Create entries for all relevant dispatcher types to ensure they are present
++// // in the final dump.
++// std::map<Dispatcher::Type, int> handle_count;
++// handle_count[Dispatcher::Type::MESSAGE_PIPE];
++// handle_count[Dispatcher::Type::DATA_PIPE_PRODUCER];
++// handle_count[Dispatcher::Type::DATA_PIPE_CONSUMER];
++// handle_count[Dispatcher::Type::SHARED_BUFFER];
++// handle_count[Dispatcher::Type::WATCHER];
++// handle_count[Dispatcher::Type::PLATFORM_HANDLE];
++// handle_count[Dispatcher::Type::INVITATION];
++
++// // Count the number of each dispatcher type.
++// {
++// base::AutoLock lock(GetLock());
++// for (const auto& entry : handles_) {
++// ++handle_count[entry.second.dispatcher->GetType()];
++// }
++// }
++
++// for (const auto& entry : handle_count) {
++// base::trace_event::MemoryAllocatorDump* inner_dump =
++// pmd->CreateAllocatorDump(std::string("mojo/") +
++// GetNameForDispatcherType(entry.first));
++// inner_dump->AddScalar(
++// base::trace_event::MemoryAllocatorDump::kNameObjectCount,
++// base::trace_event::MemoryAllocatorDump::kUnitsObjects, entry.second);
++// }
++
++// return true;
++// }
+
+ HandleTable::Entry::Entry() {}
+
+diff --git a/mojo/core/handle_table.h b/mojo/core/handle_table.h
+index 234bdac..2e0edf7 100644
+--- a/mojo/core/handle_table.h
++++ b/mojo/core/handle_table.h
+@@ -13,7 +13,7 @@
+ #include "base/gtest_prod_util.h"
+ #include "base/macros.h"
+ #include "base/synchronization/lock.h"
+-#include "base/trace_event/memory_dump_provider.h"
++// #include "base/trace_event/memory_dump_provider.h"
+ #include "mojo/core/dispatcher.h"
+ #include "mojo/core/system_impl_export.h"
+ #include "mojo/public/c/system/types.h"
+@@ -21,11 +21,10 @@
+ namespace mojo {
+ namespace core {
+
+-class MOJO_SYSTEM_IMPL_EXPORT HandleTable
+- : public base::trace_event::MemoryDumpProvider {
++class MOJO_SYSTEM_IMPL_EXPORT HandleTable {
+ public:
+ HandleTable();
+- ~HandleTable() override;
++ ~HandleTable();
+
+ // HandleTable is thread-hostile. All access should be gated by GetLock().
+ base::Lock& GetLock();
+@@ -58,11 +57,11 @@ class MOJO_SYSTEM_IMPL_EXPORT HandleTable
+ void GetActiveHandlesForTest(std::vector<MojoHandle>* handles);
+
+ private:
+- FRIEND_TEST_ALL_PREFIXES(HandleTableTest, OnMemoryDump);
++ // FRIEND_TEST_ALL_PREFIXES(HandleTableTest, OnMemoryDump);
+
+ // MemoryDumpProvider implementation.
+- bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+- base::trace_event::ProcessMemoryDump* pmd) override;
++ // bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
++ // base::trace_event::ProcessMemoryDump* pmd) override;
+
+ struct Entry {
+ Entry();
diff --git a/libchrome_tools/patch/hash.patch b/libchrome_tools/patch/hash.patch
new file mode 100644
index 000000000..34a74d68c
--- /dev/null
+++ b/libchrome_tools/patch/hash.patch
@@ -0,0 +1,21 @@
+# libchrome does not support SuperFastHash. Instead use std::hash.
+
+--- a/base/hash.cc
++++ b/base/hash.cc
+@@ -4,10 +4,12 @@
+
+ #include "base/hash.h"
+
+-// Definition in base/third_party/superfasthash/superfasthash.c. (Third-party
+-// code did not come with its own header file, so declaring the function here.)
+-// Note: This algorithm is also in Blink under Source/wtf/StringHasher.h.
+-extern "C" uint32_t SuperFastHash(const char* data, int len);
++#include <functional>
++
++uint32_t SuperFastHash(const char* data, size_t len) {
++ std::hash<std::string> hash_fn;
++ return hash_fn(std::string(data, len));
++}
+
+ namespace base {
+
diff --git a/libchrome_tools/patch/jni_registration_generator.patch b/libchrome_tools/patch/jni_registration_generator.patch
new file mode 100644
index 000000000..e385c6522
--- /dev/null
+++ b/libchrome_tools/patch/jni_registration_generator.patch
@@ -0,0 +1,13 @@
+diff --git a/base/android/jni_generator/jni_registration_generator.py b/base/android/jni_generator/jni_registration_generator.py
+index dec56ee..8c545f6 100755
+--- a/base/android/jni_generator/jni_registration_generator.py
++++ b/base/android/jni_generator/jni_registration_generator.py
+@@ -316,7 +316,7 @@ def main(argv):
+ help='The output file path.')
+ arg_parser.add_argument('--no_register_java',
+ help='A list of Java files which should be ignored '
+- 'by the parser.')
++ 'by the parser.', default=[])
+ args = arg_parser.parse_args(build_utils.ExpandFileArgs(argv[1:]))
+ args.sources_files = build_utils.ParseGnList(args.sources_files)
+
diff --git a/libchrome_tools/patch/libevent.patch b/libchrome_tools/patch/libevent.patch
new file mode 100644
index 000000000..723d62165
--- /dev/null
+++ b/libchrome_tools/patch/libevent.patch
@@ -0,0 +1,13 @@
+--- /dev/null
++++ b/base/third_party/libevent/event.h
+@@ -0,0 +1,10 @@
++// The Chromium build contains its own checkout of libevent. This stub is used
++// when building the Chrome OS or Android libchrome package to instead use the
++// system headers.
++#if defined(__ANDROID__) || defined(__ANDROID_HOST__)
++#include <event2/event.h>
++#include <event2/event_compat.h>
++#include <event2/event_struct.h>
++#else
++#include <event.h>
++#endif
diff --git a/libchrome_tools/patch/logging.patch b/libchrome_tools/patch/logging.patch
new file mode 100644
index 000000000..3a42e4c82
--- /dev/null
+++ b/libchrome_tools/patch/logging.patch
@@ -0,0 +1,78 @@
+diff --git a/base/logging.cc b/base/logging.cc
+index 8eabda0..112afb8 100644
+--- a/base/logging.cc
++++ b/base/logging.cc
+@@ -58,7 +58,7 @@ typedef HANDLE MutexHandle;
+ #include <zircon/syscalls.h>
+ #endif
+
+-#if defined(OS_ANDROID)
++#if defined(OS_ANDROID) || defined(__ANDROID__)
+ #include <android/log.h>
+ #endif
+
+@@ -407,21 +407,23 @@ bool BaseInitLoggingImpl(const LoggingSettings& settings) {
+ // Can log only to the system debug log.
+ CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0);
+ #endif
+- base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+- // Don't bother initializing |g_vlog_info| unless we use one of the
+- // vlog switches.
+- if (command_line->HasSwitch(switches::kV) ||
+- command_line->HasSwitch(switches::kVModule)) {
+- // NOTE: If |g_vlog_info| has already been initialized, it might be in use
+- // by another thread. Don't delete the old VLogInfo, just create a second
+- // one. We keep track of both to avoid memory leak warnings.
+- CHECK(!g_vlog_info_prev);
+- g_vlog_info_prev = g_vlog_info;
+-
+- g_vlog_info =
+- new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
+- command_line->GetSwitchValueASCII(switches::kVModule),
+- &g_min_log_level);
++ if (base::CommandLine::InitializedForCurrentProcess()) {
++ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
++ // Don't bother initializing |g_vlog_info| unless we use one of the
++ // vlog switches.
++ if (command_line->HasSwitch(switches::kV) ||
++ command_line->HasSwitch(switches::kVModule)) {
++ // NOTE: If |g_vlog_info| has already been initialized, it might be in use
++ // by another thread. Don't delete the old VLogInfo, just create a second
++ // one. We keep track of both to avoid memory leak warnings.
++ CHECK(!g_vlog_info_prev);
++ g_vlog_info_prev = g_vlog_info;
++
++ g_vlog_info =
++ new VlogInfo(command_line->GetSwitchValueASCII(switches::kV),
++ command_line->GetSwitchValueASCII(switches::kVModule),
++ &g_min_log_level);
++ }
+ }
+
+ g_logging_destination = settings.logging_dest;
+@@ -755,7 +757,7 @@ LogMessage::~LogMessage() {
+ str_newline.c_str());
+ #endif // defined(USE_ASL)
+ }
+-#elif defined(OS_ANDROID)
++#elif defined(OS_ANDROID) || defined(__ANDROID__)
+ android_LogPriority priority =
+ (severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN;
+ switch (severity_) {
+@@ -772,7 +774,16 @@ LogMessage::~LogMessage() {
+ priority = ANDROID_LOG_FATAL;
+ break;
+ }
++#if defined(OS_ANDROID)
+ __android_log_write(priority, "chromium", str_newline.c_str());
++#else
++ __android_log_write(
++ priority,
++ base::CommandLine::InitializedForCurrentProcess() ?
++ base::CommandLine::ForCurrentProcess()->
++ GetProgram().BaseName().value().c_str() : nullptr,
++ str_newline.c_str());
++#endif // defined(OS_ANDROID)
+ #endif
+ ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr));
+ fflush(stderr);
diff --git a/libchrome_tools/patch/macros.patch b/libchrome_tools/patch/macros.patch
new file mode 100644
index 000000000..0d608bb30
--- /dev/null
+++ b/libchrome_tools/patch/macros.patch
@@ -0,0 +1,72 @@
+diff --git a/base/macros.h b/base/macros.h
+index 3064a1b..8685117 100644
+--- a/base/macros.h
++++ b/base/macros.h
+@@ -12,6 +12,13 @@
+
+ #include <stddef.h> // For size_t.
+
++#if defined(ANDROID)
++// Prefer Android's libbase definitions to our own.
++#include <android-base/macros.h>
++#endif // defined(ANDROID)
++
++// We define following macros conditionally as they may be defined by another libraries.
++
+ // Distinguish mips32.
+ #if defined(__mips__) && (_MIPS_SIM == _ABIO32) && !defined(__mips32__)
+ #define __mips32__
+@@ -23,23 +30,31 @@
+ #endif
+
+ // Put this in the declarations for a class to be uncopyable.
++#if !defined(DISALLOW_COPY)
+ #define DISALLOW_COPY(TypeName) \
+ TypeName(const TypeName&) = delete
++#endif
+
+ // Put this in the declarations for a class to be unassignable.
++#if !defined(DISALLOW_ASSIGN)
+ #define DISALLOW_ASSIGN(TypeName) TypeName& operator=(const TypeName&) = delete
++#endif
+
+ // Put this in the declarations for a class to be uncopyable and unassignable.
++#if !defined(DISALLOW_COPY_AND_ASSIGN)
+ #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
+ DISALLOW_COPY(TypeName); \
+ DISALLOW_ASSIGN(TypeName)
++#endif
+
+ // A macro to disallow all the implicit constructors, namely the
+ // default constructor, copy constructor and operator= functions.
+ // This is especially useful for classes containing only static methods.
++#if !defined(DISALLOW_IMPLICIT_CONSTRUCTORS)
+ #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+ TypeName() = delete; \
+ DISALLOW_COPY_AND_ASSIGN(TypeName)
++#endif
+
+ // The arraysize(arr) macro returns the # of elements in an array arr. The
+ // expression is a compile-time constant, and therefore can be used in defining
+@@ -53,8 +68,10 @@
+ //
+ // DEPRECATED, please use base::size(array) instead.
+ // TODO(https://crbug.com/837308): Replace existing arraysize usages.
++#if !defined(arraysize)
+ template <typename T, size_t N> char (&ArraySizeHelper(T (&array)[N]))[N];
+ #define arraysize(array) (sizeof(ArraySizeHelper(array)))
++#endif
+
+ // Used to explicitly mark the return value of a function as unused. If you are
+ // really sure you don't want to do anything with the return value of a function
+@@ -83,8 +100,10 @@ namespace base {
+ // return *instance;
+ // }
+ // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
++#if !defined(CR_DEFINE_STATIC_LOCAL)
+ #define CR_DEFINE_STATIC_LOCAL(type, name, arguments) \
+ static type& name = *new type arguments
++#endif
+
+ // Workaround for MSVC, which expands __VA_ARGS__ as one macro argument. To
+ // work around this bug, wrap the entire expression in this macro...
diff --git a/libchrome_tools/patch/memory_linux.patch b/libchrome_tools/patch/memory_linux.patch
new file mode 100644
index 000000000..09afb42d1
--- /dev/null
+++ b/libchrome_tools/patch/memory_linux.patch
@@ -0,0 +1,17 @@
+# this file used to have a bunch of __libc_* extern definitions, android complains only about this one as missing
+
+diff --git a/base/process/memory_linux.cc b/base/process/memory_linux.cc
+index 171753c..11e482b 100644
+--- a/base/process/memory_linux.cc
++++ b/base/process/memory_linux.cc
+@@ -22,6 +22,10 @@
+ #include "third_party/tcmalloc/gperftools-2.0/chromium/src/gperftools/tcmalloc.h"
+ #endif
+
++extern "C" {
++void* __libc_malloc(size_t size);
++}
++
+ namespace base {
+
+ size_t g_oom_size = 0U;
diff --git a/libchrome_tools/patch/message_loop.patch b/libchrome_tools/patch/message_loop.patch
new file mode 100644
index 000000000..c06107a94
--- /dev/null
+++ b/libchrome_tools/patch/message_loop.patch
@@ -0,0 +1,23 @@
+--- a/base/message_loop/message_loop.h
++++ b/base/message_loop/message_loop.h
+@@ -28,6 +28,11 @@
+ #include "base/time/time.h"
+ #include "build/build_config.h"
+
++// Just in libchrome
++namespace brillo {
++class BaseMessageLoop;
++}
++
+ namespace base {
+
+ class ThreadTaskRunnerHandle;
+@@ -214,6 +219,8 @@ class BASE_EXPORT MessageLoop : public MessagePump::Delegate,
+ void BindToCurrentThread();
+
+ private:
++ //only in libchrome
++ friend class brillo::BaseMessageLoop;
+ friend class internal::IncomingTaskQueue;
+ friend class MessageLoopCurrent;
+ friend class MessageLoopCurrentForIO;
diff --git a/libchrome_tools/patch/message_loop_unittest.patch b/libchrome_tools/patch/message_loop_unittest.patch
new file mode 100644
index 000000000..cc5b5de95
--- /dev/null
+++ b/libchrome_tools/patch/message_loop_unittest.patch
@@ -0,0 +1,125 @@
+diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
+index 1a21fc5..7743479 100644
+--- a/base/message_loop/message_loop_unittest.cc
++++ b/base/message_loop/message_loop_unittest.cc
+@@ -22,7 +22,8 @@
+ #include "base/run_loop.h"
+ #include "base/single_thread_task_runner.h"
+ #include "base/synchronization/waitable_event.h"
+-#include "base/task_scheduler/task_scheduler.h"
++// Unsupported in libchrome
++// #include "base/task_scheduler/task_scheduler.h"
+ #include "base/test/gtest_util.h"
+ #include "base/test/test_simple_task_runner.h"
+ #include "base/test/test_timeouts.h"
+@@ -260,7 +261,8 @@ void PostNTasks(int posts_remaining) {
+
+ enum class TaskSchedulerAvailability {
+ NO_TASK_SCHEDULER,
+- WITH_TASK_SCHEDULER,
++ // Unsupported in libchrome.
++ // WITH_TASK_SCHEDULER,
+ };
+
+ std::string TaskSchedulerAvailabilityToString(
+@@ -268,8 +270,9 @@ std::string TaskSchedulerAvailabilityToString(
+ switch (availability) {
+ case TaskSchedulerAvailability::NO_TASK_SCHEDULER:
+ return "NoTaskScheduler";
+- case TaskSchedulerAvailability::WITH_TASK_SCHEDULER:
+- return "WithTaskScheduler";
++ // Unsupported in libchrome.
++ // case TaskSchedulerAvailability::WITH_TASK_SCHEDULER:
++ // return "WithTaskScheduler";
+ }
+ NOTREACHED();
+ return "Unknown";
+@@ -282,11 +285,16 @@ class MessageLoopTest
+ ~MessageLoopTest() override = default;
+
+ void SetUp() override {
++ // Unsupported in libchrome.
++#if 0
+ if (GetParam() == TaskSchedulerAvailability::WITH_TASK_SCHEDULER)
+ TaskScheduler::CreateAndStartWithDefaultParams("MessageLoopTest");
++#endif
+ }
+
+ void TearDown() override {
++ // Unsupported in libchrome.
++#if 0
+ if (GetParam() == TaskSchedulerAvailability::WITH_TASK_SCHEDULER) {
+ // Failure to call FlushForTesting() could result in task leaks as tasks
+ // are skipped on shutdown.
+@@ -295,6 +303,7 @@ class MessageLoopTest
+ base::TaskScheduler::GetInstance()->JoinForTesting();
+ base::TaskScheduler::SetInstance(nullptr);
+ }
++#endif
+ }
+
+ static std::string ParamInfoToString(
+@@ -776,13 +785,18 @@ class MessageLoopTypedTest
+ ~MessageLoopTypedTest() = default;
+
+ void SetUp() override {
++// Unsupported in libchrome.
++#if 0
+ if (GetTaskSchedulerAvailability() ==
+ TaskSchedulerAvailability::WITH_TASK_SCHEDULER) {
+ TaskScheduler::CreateAndStartWithDefaultParams("MessageLoopTypedTest");
+ }
++#endif
+ }
+
+ void TearDown() override {
++// Unsupported in libchrome.
++#if 0
+ if (GetTaskSchedulerAvailability() ==
+ TaskSchedulerAvailability::WITH_TASK_SCHEDULER) {
+ // Failure to call FlushForTesting() could result in task leaks as tasks
+@@ -792,6 +806,7 @@ class MessageLoopTypedTest
+ base::TaskScheduler::GetInstance()->JoinForTesting();
+ base::TaskScheduler::SetInstance(nullptr);
+ }
++#endif
+ }
+
+ static std::string ParamInfoToString(
+@@ -1769,8 +1784,10 @@ INSTANTIATE_TEST_CASE_P(
+ TaskSchedulerAvailability::NO_TASK_SCHEDULER),
+ MessageLoopTypedTestParams(
+ MessageLoop::TYPE_UI,
+- TaskSchedulerAvailability::NO_TASK_SCHEDULER),
+- MessageLoopTypedTestParams(
++ TaskSchedulerAvailability::NO_TASK_SCHEDULER)
++// Unsupported in libchrome.
++#if 0
++ ,MessageLoopTypedTestParams(
+ MessageLoop::TYPE_DEFAULT,
+ TaskSchedulerAvailability::WITH_TASK_SCHEDULER),
+ MessageLoopTypedTestParams(
+@@ -1778,7 +1795,9 @@ INSTANTIATE_TEST_CASE_P(
+ TaskSchedulerAvailability::WITH_TASK_SCHEDULER),
+ MessageLoopTypedTestParams(
+ MessageLoop::TYPE_UI,
+- TaskSchedulerAvailability::WITH_TASK_SCHEDULER)),
++ TaskSchedulerAvailability::WITH_TASK_SCHEDULER)
++#endif
++ ),
+ MessageLoopTypedTest::ParamInfoToString);
+
+ #if defined(OS_WIN)
+@@ -2210,8 +2229,10 @@ TEST_P(MessageLoopTest, SequenceLocalStorageDifferentMessageLoops) {
+ INSTANTIATE_TEST_CASE_P(
+ ,
+ MessageLoopTest,
+- ::testing::Values(TaskSchedulerAvailability::NO_TASK_SCHEDULER,
+- TaskSchedulerAvailability::WITH_TASK_SCHEDULER),
++ ::testing::Values(TaskSchedulerAvailability::NO_TASK_SCHEDULER
++ // Unsupported in libchrome
++ //, TaskSchedulerAvailability::WITH_TASK_SCHEDULER
++ ),
+ MessageLoopTest::ParamInfoToString);
+
+ namespace {
diff --git a/libchrome_tools/patch/message_pump_for_ui.patch b/libchrome_tools/patch/message_pump_for_ui.patch
new file mode 100644
index 000000000..1cf6aa0d4
--- /dev/null
+++ b/libchrome_tools/patch/message_pump_for_ui.patch
@@ -0,0 +1,28 @@
+diff --git a/base/message_loop/message_pump_for_ui.h b/base/message_loop/message_pump_for_ui.h
+index 6ee02b0..c661166 100644
+--- a/base/message_loop/message_pump_for_ui.h
++++ b/base/message_loop/message_pump_for_ui.h
+@@ -18,9 +18,9 @@
+ #include "base/message_loop/message_pump.h"
+ #elif defined(OS_NACL) || defined(OS_AIX)
+ // No MessagePumpForUI, see below.
+-#elif defined(USE_GLIB)
++#elif defined(USE_GLIB) && !defined(ANDROID)
+ #include "base/message_loop/message_pump_glib.h"
+-#elif defined(OS_LINUX) || defined(OS_BSD)
++#elif defined(OS_LINUX) || defined(OS_BSD)|| defined(ANDROID)
+ #include "base/message_loop/message_pump_libevent.h"
+ #elif defined(OS_FUCHSIA)
+ #include "base/message_loop/message_pump_fuchsia.h"
+@@ -42,9 +42,9 @@ using MessagePumpForUI = MessagePump;
+ #elif defined(OS_NACL) || defined(OS_AIX)
+ // Currently NaCl and AIX don't have a MessagePumpForUI.
+ // TODO(abarth): Figure out if we need this.
+-#elif defined(USE_GLIB)
++#elif defined(USE_GLIB) && !defined(ANDROID)
+ using MessagePumpForUI = MessagePumpGlib;
+-#elif defined(OS_LINUX) || defined(OS_BSD)
++#elif defined(OS_LINUX) || defined(OS_BSD) || defined(ANDROID)
+ using MessagePumpForUI = MessagePumpLibevent;
+ #elif defined(OS_FUCHSIA)
+ using MessagePumpForUI = MessagePumpFuchsia;
diff --git a/libchrome_tools/patch/modp_b64.patch b/libchrome_tools/patch/modp_b64.patch
new file mode 100644
index 000000000..89d838c85
--- /dev/null
+++ b/libchrome_tools/patch/modp_b64.patch
@@ -0,0 +1,19 @@
+--- /dev/null
++++ b/third_party/modp_b64/modp_b64.h
+@@ -0,0 +1,16 @@
++// Copyright (C) 2018 The Android Open Source Project
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++
++// Redirect to system header.
++#include <modp_b64/modp_b64.h>
diff --git a/libchrome_tools/patch/mojo-Add-a-way-to-create-thread-safe-interfaces-in-Java.patch b/libchrome_tools/patch/mojo-Add-a-way-to-create-thread-safe-interfaces-in-Java.patch
new file mode 100644
index 000000000..761029392
--- /dev/null
+++ b/libchrome_tools/patch/mojo-Add-a-way-to-create-thread-safe-interfaces-in-Java.patch
@@ -0,0 +1,137 @@
+From 225f21f660b943ff9ade13b0d114e8ba3b3036d5 Mon Sep 17 00:00:00 2001
+From: Luis Hector Chavez <lhchavez@google.com>
+Date: Fri, 20 Jul 2018 09:39:22 -0700
+Subject: [PATCH] Mojo: Add a way to create thread-safe interfaces in Java
+
+This change adds Interface.Manager.buildThreadSafeProxy(), which is
+roughly analogous to mojo::ThreadSafeInterfacePtr<T>. Given that Java
+does not have move-only semantics, the Proxy object that is passed is
+unbound and a new object is returned.
+
+Bug: 810084
+Test: cheets_ContainerSmokeTest in Chrome OS
+Change-Id: I6565f9e526e3fa8f8cb222cb8cd11e95bb57f7d3
+Reviewed-on: https://chromium-review.googlesource.com/1147320
+Reviewed-by: Ken Rockot <rockot@chromium.org>
+Commit-Queue: Luis Hector Chavez <lhchavez@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#577429}
+---
+ .../org/chromium/mojo/bindings/Interface.java | 88 +++++++++++++++++++
+ 1 file changed, 88 insertions(+)
+
+diff --git a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
+index e3be8b3..f7d3f80 100644
+--- a/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
++++ b/mojo/public/java/bindings/src/org/chromium/mojo/bindings/Interface.java
+@@ -20,6 +20,7 @@ import org.chromium.mojo.system.MojoException;
+ import org.chromium.mojo.system.Pair;
+
+ import java.io.Closeable;
++import java.util.concurrent.Executor;
+
+ /**
+ * Base class for mojo generated interfaces.
+@@ -317,6 +318,67 @@ public interface Interface extends ConnectionErrorHandler, Closeable {
+
+ }
+
++ /**
++ * A {@link MessageReceiverWithResponder} implementation that forwards all calls to the thread
++ * the ThreadSafeForwarder was created.
++ */
++ class ThreadSafeForwarder implements MessageReceiverWithResponder {
++
++ /**
++ * The {@link MessageReceiverWithResponder} that will receive a serialized message for
++ * each method call.
++ */
++ private final MessageReceiverWithResponder mMessageReceiver;
++
++ /**
++ * The {@link Executor} to forward all tasks to.
++ */
++ private final Executor mExecutor;
++
++ /**
++ * Constructor.
++ *
++ * @param core the Core implementation used to create pipes and access the async waiter.
++ * @param messageReceiver the message receiver to send message to.
++ */
++ public ThreadSafeForwarder(Core core, MessageReceiverWithResponder messageReceiver) {
++ mMessageReceiver = messageReceiver;
++ mExecutor = ExecutorFactory.getExecutorForCurrentThread(core);
++ }
++
++ /**
++ * @see org.chromium.mojo.bindings.MessageReceiver#close()
++ */
++ @Override
++ public void close() {
++ mExecutor.execute(() -> {
++ mMessageReceiver.close();
++ });
++ }
++
++ /**
++ * @see org.chromium.mojo.bindings.MessageReceiver#accept()
++ */
++ @Override
++ public boolean accept(Message message) {
++ mExecutor.execute(() -> {
++ mMessageReceiver.accept(message);
++ });
++ return true;
++ }
++
++ /**
++ * @see org.chromium.mojo.bindings.MessageReceiverWithResponder#acceptWithResponder()
++ */
++ @Override
++ public boolean acceptWithResponder(Message message, MessageReceiver responder) {
++ mExecutor.execute(() -> {
++ mMessageReceiver.acceptWithResponder(message, responder);
++ });
++ return true;
++ }
++ }
++
+ /**
+ * The |Manager| object enables building of proxies and stubs for a given interface.
+ *
+@@ -385,6 +447,32 @@ public interface Interface extends ConnectionErrorHandler, Closeable {
+ return new InterfaceRequest<I>(handle);
+ }
+
++ /**
++ * Constructs a thread-safe Proxy forwarding the calls to the given message receiver.
++ * All calls can be performed from any thread and are posted to the {@link Executor} that
++ * is associated with the thread on which this method was called on.
++ *
++ * The original Proxy object is unbound.
++ */
++ public final P buildThreadSafeProxy(P proxy) {
++ HandlerImpl handlerImpl = (HandlerImpl) proxy.getProxyHandler();
++ Core core = handlerImpl.getCore();
++ int version = handlerImpl.getVersion();
++
++ Router router = new RouterImpl(handlerImpl.passHandle());
++ // Close the original proxy now that its handle has been passed.
++ proxy.close();
++
++ proxy = buildProxy(
++ core, new ThreadSafeForwarder(core, new AutoCloseableRouter(core, router)));
++ DelegatingConnectionErrorHandler handlers = new DelegatingConnectionErrorHandler();
++ handlers.addConnectionErrorHandler(proxy);
++ router.setErrorHandler(handlers);
++ router.start();
++ ((HandlerImpl) proxy.getProxyHandler()).setVersion(version);
++ return proxy;
++ }
++
+ /**
+ * Binds the implementation to the given |router|.
+ */
+--
+2.19.0.605.g01d371f741-goog
+
diff --git a/libchrome_tools/patch/mojo.patch b/libchrome_tools/patch/mojo.patch
new file mode 100644
index 000000000..8040fbe9e
--- /dev/null
+++ b/libchrome_tools/patch/mojo.patch
@@ -0,0 +1,38 @@
+# Local patches for libmojo.
+
+--- a/base/android/jni_android.cc
++++ b/base/android/jni_android.cc
+@@ -253,7 +253,11 @@ void CheckException(JNIEnv* env) {
+ }
+
+ // Now, feel good about it and die.
+- LOG(FATAL) << "Please include Java exception stack in crash report";
++ // TODO(lhchavez): Remove this hack. See b/28814913 for details.
++ if (java_throwable)
++ LOG(FATAL) << GetJavaExceptionInfo(env, java_throwable);
++ else
++ LOG(FATAL) << "Unhandled exception";
+ }
+
+ std::string GetJavaExceptionInfo(JNIEnv* env, jthrowable java_throwable) {
+--- a/build/android/gyp/util/build_utils.py
++++ b/build/android/gyp/util/build_utils.py
+@@ -25,8 +25,16 @@ import zipfile
+ # Some clients do not add //build/android/gyp to PYTHONPATH.
+ import md5_check # pylint: disable=relative-import
+
+-sys.path.append(os.path.join(os.path.dirname(__file__),
+- os.pardir, os.pardir, os.pardir))
++# pylib conflicts with mojo/public/tools/bindings/pylib. Prioritize
++# build/android/pylib.
++# PYTHONPATH wouldn't help in this case, because soong put source files under
++# temp directory for each build, so the abspath is unknown until the
++# execution.
++#sys.path.append(os.path.join(os.path.dirname(__file__),
++# os.pardir, os.pardir, os.pardir))
++sys.path.insert(0, os.path.join(os.path.dirname(__file__),
++ os.pardir, os.pardir))
++
+ import gn_helpers
+
+ # Definition copied from pylib/constants/__init__.py to avoid adding
diff --git a/libchrome_tools/patch/mojom_disable_trace_and_mem_dump.patch b/libchrome_tools/patch/mojom_disable_trace_and_mem_dump.patch
new file mode 100644
index 000000000..9724e1d35
--- /dev/null
+++ b/libchrome_tools/patch/mojom_disable_trace_and_mem_dump.patch
@@ -0,0 +1,299 @@
+diff --git a/mojo/core/core.cc b/mojo/core/core.cc
+index 8422ec2..3ffa640 100644
+--- a/mojo/core/core.cc
++++ b/mojo/core/core.cc
+@@ -21,7 +21,7 @@
+ #include "base/strings/string_piece.h"
+ #include "base/threading/thread_task_runner_handle.h"
+ #include "base/time/time.h"
+-#include "base/trace_event/memory_dump_manager.h"
++// #include "base/trace_event/memory_dump_manager.h"
+ #include "build/build_config.h"
+ #include "mojo/core/channel.h"
+ #include "mojo/core/configuration.h"
+@@ -127,8 +127,8 @@ void RunMojoProcessErrorHandler(ProcessDisconnectHandler* disconnect_handler,
+
+ Core::Core() {
+ handles_.reset(new HandleTable);
+- base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+- handles_.get(), "MojoHandleTable", nullptr);
++ // base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
++ // handles_.get(), "MojoHandleTable", nullptr);
+ }
+
+ Core::~Core() {
+@@ -142,8 +142,8 @@ Core::~Core() {
+ base::BindOnce(&Core::PassNodeControllerToIOThread,
+ base::Passed(&node_controller_)));
+ }
+- base::trace_event::MemoryDumpManager::GetInstance()
+- ->UnregisterAndDeleteDumpProviderSoon(std::move(handles_));
++ // base::trace_event::MemoryDumpManager::GetInstance()
++ // ->UnregisterAndDeleteDumpProviderSoon(std::move(handles_));
+ }
+
+ void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) {
+diff --git a/mojo/core/user_message_impl.cc b/mojo/core/user_message_impl.cc
+index d4a4da1..9cb8284 100644
+--- a/mojo/core/user_message_impl.cc
++++ b/mojo/core/user_message_impl.cc
+@@ -13,10 +13,10 @@
+ #include "base/no_destructor.h"
+ #include "base/numerics/safe_conversions.h"
+ #include "base/numerics/safe_math.h"
+-#include "base/trace_event/memory_allocator_dump.h"
+-#include "base/trace_event/memory_dump_manager.h"
+-#include "base/trace_event/memory_dump_provider.h"
+-#include "base/trace_event/trace_event.h"
++// #include "base/trace_event/memory_allocator_dump.h"
++// #include "base/trace_event/memory_dump_manager.h"
++// #include "base/trace_event/memory_dump_provider.h"
++// #include "base/trace_event/trace_event.h"
+ #include "mojo/core/core.h"
+ #include "mojo/core/node_channel.h"
+ #include "mojo/core/node_controller.h"
+@@ -271,36 +271,36 @@ void DecrementMessageCount() {
+ base::subtle::NoBarrier_AtomicIncrement(&g_message_count, -1);
+ }
+
+-class MessageMemoryDumpProvider : public base::trace_event::MemoryDumpProvider {
+- public:
+- MessageMemoryDumpProvider() {
+- base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
+- this, "MojoMessages", nullptr);
+- }
+-
+- ~MessageMemoryDumpProvider() override {
+- base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
+- this);
+- }
+-
+- private:
+- // base::trace_event::MemoryDumpProvider:
+- bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
+- base::trace_event::ProcessMemoryDump* pmd) override {
+- auto* dump = pmd->CreateAllocatorDump("mojo/messages");
+- dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
+- base::trace_event::MemoryAllocatorDump::kUnitsObjects,
+- base::subtle::NoBarrier_Load(&g_message_count));
+- return true;
+- }
+-
+- DISALLOW_COPY_AND_ASSIGN(MessageMemoryDumpProvider);
+-};
+-
+-void EnsureMemoryDumpProviderExists() {
+- static base::NoDestructor<MessageMemoryDumpProvider> provider;
+- ALLOW_UNUSED_LOCAL(provider);
+-}
++// class MessageMemoryDumpProvider : public base::trace_event::MemoryDumpProvider {
++// public:
++// MessageMemoryDumpProvider() {
++// base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
++// this, "MojoMessages", nullptr);
++// }
++
++// ~MessageMemoryDumpProvider() override {
++// base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
++// this);
++// }
++
++// private:
++// // base::trace_event::MemoryDumpProvider:
++// bool OnMemoryDump(const base::trace_event::MemoryDumpArgs& args,
++// base::trace_event::ProcessMemoryDump* pmd) override {
++// auto* dump = pmd->CreateAllocatorDump("mojo/messages");
++// dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameObjectCount,
++// base::trace_event::MemoryAllocatorDump::kUnitsObjects,
++// base::subtle::NoBarrier_Load(&g_message_count));
++// return true;
++// }
++
++// DISALLOW_COPY_AND_ASSIGN(MessageMemoryDumpProvider);
++// };
++
++// void EnsureMemoryDumpProviderExists() {
++// static base::NoDestructor<MessageMemoryDumpProvider> provider;
++// ALLOW_UNUSED_LOCAL(provider);
++// }
+
+ } // namespace
+
+@@ -648,7 +648,7 @@ void UserMessageImpl::FailHandleSerializationForTesting(bool fail) {
+
+ UserMessageImpl::UserMessageImpl(ports::UserMessageEvent* message_event)
+ : ports::UserMessage(&kUserMessageTypeInfo), message_event_(message_event) {
+- EnsureMemoryDumpProviderExists();
++ // EnsureMemoryDumpProviderExists();
+ IncrementMessageCount();
+ }
+
+@@ -667,7 +667,7 @@ UserMessageImpl::UserMessageImpl(ports::UserMessageEvent* message_event,
+ header_size_(header_size),
+ user_payload_(user_payload),
+ user_payload_size_(user_payload_size) {
+- EnsureMemoryDumpProviderExists();
++ // EnsureMemoryDumpProviderExists();
+ IncrementMessageCount();
+ }
+
+diff --git a/mojo/public/cpp/bindings/lib/message_dumper.cc b/mojo/public/cpp/bindings/lib/message_dumper.cc
+index f187e45..35696bb 100644
+--- a/mojo/public/cpp/bindings/lib/message_dumper.cc
++++ b/mojo/public/cpp/bindings/lib/message_dumper.cc
+@@ -22,33 +22,33 @@ base::FilePath& DumpDirectory() {
+ return *dump_directory;
+ }
+
+-void WriteMessage(uint32_t identifier,
+- const mojo::MessageDumper::MessageEntry& entry) {
+- static uint64_t num = 0;
+-
+- if (!entry.interface_name)
+- return;
+-
+- base::FilePath message_directory =
+- DumpDirectory()
+- .AppendASCII(entry.interface_name)
+- .AppendASCII(base::NumberToString(identifier));
+-
+- if (!base::DirectoryExists(message_directory) &&
+- !base::CreateDirectory(message_directory)) {
+- LOG(ERROR) << "Failed to create" << message_directory.value();
+- return;
+- }
+-
+- std::string filename =
+- base::NumberToString(num++) + "." + entry.method_name + ".mojomsg";
+- base::FilePath path = message_directory.AppendASCII(filename);
+- base::File file(path,
+- base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS);
+-
+- file.WriteAtCurrentPos(reinterpret_cast<const char*>(entry.data_bytes.data()),
+- static_cast<int>(entry.data_bytes.size()));
+-}
++// void WriteMessage(uint32_t identifier,
++// const mojo::MessageDumper::MessageEntry& entry) {
++// static uint64_t num = 0;
++
++// if (!entry.interface_name)
++// return;
++
++// base::FilePath message_directory =
++// DumpDirectory()
++// .AppendASCII(entry.interface_name)
++// .AppendASCII(base::NumberToString(identifier));
++
++// if (!base::DirectoryExists(message_directory) &&
++// !base::CreateDirectory(message_directory)) {
++// LOG(ERROR) << "Failed to create" << message_directory.value();
++// return;
++// }
++
++// std::string filename =
++// base::NumberToString(num++) + "." + entry.method_name + ".mojomsg";
++// base::FilePath path = message_directory.AppendASCII(filename);
++// base::File file(path,
++// base::File::FLAG_WRITE | base::File::FLAG_CREATE_ALWAYS);
++
++// file.WriteAtCurrentPos(reinterpret_cast<const char*>(entry.data_bytes.data()),
++// static_cast<int>(entry.data_bytes.size()));
++// }
+
+ } // namespace
+
+@@ -71,17 +71,17 @@ MessageDumper::MessageDumper() : identifier_(base::RandUint64()) {}
+ MessageDumper::~MessageDumper() {}
+
+ bool MessageDumper::Accept(mojo::Message* message) {
+- MessageEntry entry(message->data(), message->data_num_bytes(),
+- message->interface_name(), message->method_name());
++ // MessageEntry entry(message->data(), message->data_num_bytes(),
++ // "unknown interface", "unknown name");
+
+- static base::NoDestructor<scoped_refptr<base::TaskRunner>> task_runner(
+- base::CreateSequencedTaskRunnerWithTraits(
+- {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
+- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
++ // static base::NoDestructor<scoped_refptr<base::TaskRunner>> task_runner(
++ // base::CreateSequencedTaskRunnerWithTraits(
++ // {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
++ // base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
+
+- (*task_runner)
+- ->PostTask(FROM_HERE,
+- base::BindOnce(&WriteMessage, identifier_, std::move(entry)));
++ // (*task_runner)
++ // ->PostTask(FROM_HERE,
++ // base::BindOnce(&WriteMessage, identifier_, std::move(entry)));
+ return true;
+ }
+
+diff --git a/mojo/public/cpp/system/file_data_pipe_producer.cc b/mojo/public/cpp/system/file_data_pipe_producer.cc
+index 842fe8f..6038bbe 100644
+--- a/mojo/public/cpp/system/file_data_pipe_producer.cc
++++ b/mojo/public/cpp/system/file_data_pipe_producer.cc
+@@ -266,13 +266,15 @@ void FileDataPipeProducer::WriteFromPath(const base::FilePath& path,
+
+ void FileDataPipeProducer::InitializeNewRequest(CompletionCallback callback) {
+ DCHECK(!file_sequence_state_);
+- auto file_task_runner = base::CreateSequencedTaskRunnerWithTraits(
+- {base::MayBlock(), base::TaskPriority::BACKGROUND});
+- file_sequence_state_ = new FileSequenceState(
+- std::move(producer_), file_task_runner,
+- base::BindOnce(&FileDataPipeProducer::OnWriteComplete,
+- weak_factory_.GetWeakPtr(), std::move(callback)),
+- base::SequencedTaskRunnerHandle::Get(), std::move(observer_));
++
++ LOG(FATAL) << "unsupported in libchrome";
++ // auto file_task_runner = base::CreateSequencedTaskRunnerWithTraits(
++ // {base::MayBlock(), base::TaskPriority::BACKGROUND});
++ // file_sequence_state_ = new FileSequenceState(
++ // std::move(producer_), file_task_runner,
++ // base::BindOnce(&FileDataPipeProducer::OnWriteComplete,
++ // weak_factory_.GetWeakPtr(), std::move(callback)),
++ // base::SequencedTaskRunnerHandle::Get(), std::move(observer_));
+ }
+
+ void FileDataPipeProducer::OnWriteComplete(
+diff --git a/mojo/public/tools/bindings/mojom_bindings_generator.py b/mojo/public/tools/bindings/mojom_bindings_generator.py
+index affbe79..57a8031 100755
+--- a/mojo/public/tools/bindings/mojom_bindings_generator.py
++++ b/mojo/public/tools/bindings/mojom_bindings_generator.py
+@@ -174,7 +174,8 @@ class MojomProcessor(object):
+ MakeImportStackMessage(imported_filename_stack + [rel_filename.path])
+ sys.exit(1)
+
+- tree = _UnpickleAST(_GetPicklePath(rel_filename, args.output_dir))
++ tree = _UnpickleAST(_FindPicklePath(rel_filename, args.gen_directories +
++ [args.output_dir]))
+ dirname = os.path.dirname(rel_filename.path)
+
+ # Process all our imports first and collect the module object for each.
+@@ -256,6 +257,16 @@ def _Generate(args, remaining_args):
+ return 0
+
+
++def _FindPicklePath(rel_filename, search_dirs):
++ filename, _ = os.path.splitext(rel_filename.relative_path())
++ pickle_path = filename + '.p'
++ for search_dir in search_dirs:
++ path = os.path.join(search_dir, pickle_path)
++ if os.path.isfile(path):
++ return path
++ raise Exception("%s: Error: Could not find file in %r" % (pickle_path, search_dirs))
++
++
+ def _GetPicklePath(rel_filename, output_dir):
+ filename, _ = os.path.splitext(rel_filename.relative_path())
+ pickle_path = filename + '.p'
+@@ -402,6 +413,9 @@ def main():
+ metavar="GENERATORS",
+ default="c++,javascript,java",
+ help="comma-separated list of generators")
++ generate_parser.add_argument(
++ "--gen_dir", dest="gen_directories", action="append", metavar="directory",
++ default=[], help="add a directory to be searched for the syntax trees.")
+ generate_parser.add_argument(
+ "-I", dest="import_directories", action="append", metavar="directory",
+ default=[],
diff --git a/libchrome_tools/patch/observer_list_unittest.patch b/libchrome_tools/patch/observer_list_unittest.patch
new file mode 100644
index 000000000..8b1c5b5ae
--- /dev/null
+++ b/libchrome_tools/patch/observer_list_unittest.patch
@@ -0,0 +1,65 @@
+diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
+index 1470b90..50d7e7e 100644
+--- a/base/observer_list_unittest.cc
++++ b/base/observer_list_unittest.cc
+@@ -17,9 +17,11 @@
+ #include "base/run_loop.h"
+ #include "base/sequenced_task_runner.h"
+ #include "base/single_thread_task_runner.h"
++#include "base/strings/string_piece.h"
+ #include "base/synchronization/waitable_event.h"
+-#include "base/task_scheduler/post_task.h"
+-#include "base/task_scheduler/task_scheduler.h"
++// TaskScheduler not supported in libchrome
++// #include "base/task_scheduler/post_task.h"
++// #include "base/task_scheduler/task_scheduler.h"
+ #include "base/test/gtest_util.h"
+ #include "base/test/scoped_task_environment.h"
+ #include "base/threading/platform_thread.h"
+@@ -690,6 +692,8 @@ class SequenceVerificationObserver : public Foo {
+ } // namespace
+
+ // Verify that observers are notified on the correct sequence.
++// TaskScheduler not supported in libchrome
++#if 0
+ TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) {
+ test::ScopedTaskEnvironment scoped_task_environment;
+
+@@ -717,9 +721,12 @@ TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) {
+ EXPECT_TRUE(observer_1.called_on_valid_sequence());
+ EXPECT_TRUE(observer_2.called_on_valid_sequence());
+ }
++#endif
+
+ // Verify that when an observer is added to a NOTIFY_ALL ObserverListThreadSafe
+ // from a notification, it is itself notified.
++// TaskScheduler not supported in libchrome
++#if 0
+ TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) {
+ test::ScopedTaskEnvironment scoped_task_environment;
+ auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
+@@ -737,6 +744,7 @@ TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) {
+
+ EXPECT_EQ(1, observer_added_from_notification.GetValue());
+ }
++#endif
+
+ namespace {
+
+@@ -769,6 +777,8 @@ class RemoveWhileNotificationIsRunningObserver : public Foo {
+
+ // Verify that there is no crash when an observer is removed while it is being
+ // notified.
++// TaskScheduler not supported in libchrome
++#if 0
+ TEST(ObserverListThreadSafeTest, RemoveWhileNotificationIsRunning) {
+ auto observer_list = MakeRefCounted<ObserverListThreadSafe<Foo>>();
+ RemoveWhileNotificationIsRunningObserver observer;
+@@ -793,6 +803,7 @@ TEST(ObserverListThreadSafeTest, RemoveWhileNotificationIsRunning) {
+
+ observer.Unblock();
+ }
++#endif
+
+ TEST(ObserverListTest, Existing) {
+ ObserverList<Foo> observer_list(ObserverListPolicy::EXISTING_ONLY);
diff --git a/libchrome_tools/patch/path_service.patch b/libchrome_tools/patch/path_service.patch
new file mode 100644
index 000000000..466635dce
--- /dev/null
+++ b/libchrome_tools/patch/path_service.patch
@@ -0,0 +1,83 @@
+# Several paths are not supported in PathService by libchrome.
+
+--- a/base/base_paths_posix.cc
++++ b/base/base_paths_posix.cc
+@@ -19,7 +19,8 @@
+ #include "base/files/file_path.h"
+ #include "base/files/file_util.h"
+ #include "base/logging.h"
+-#include "base/nix/xdg_util.h"
++// Unused, and this file is not ported to libchrome.
++// #include "base/nix/xdg_util.h"
+ #include "base/path_service.h"
+ #include "base/process/process_metrics.h"
+ #include "build/build_config.h"
+@@ -77,6 +78,8 @@ bool PathProviderPosix(int key, FilePath
+ return true;
+ #endif
+ }
++// Following paths are not supported in libchrome/libmojo.
++#if 0
+ case DIR_SOURCE_ROOT: {
+ // Allow passing this in the environment, for more flexibility in build
+ // tree configurations (sub-project builds, gyp --output_dir, etc.)
+@@ -112,6 +115,7 @@ bool PathProviderPosix(int key, FilePath
+ *result = cache_dir;
+ return true;
+ }
++#endif
+ }
+ return false;
+ }
+--- a/base/files/file_util_posix.cc
++++ b/base/files/file_util_posix.cc
+@@ -594,6 +594,9 @@ bool GetTempDir(FilePath* path) {
+
+ #if defined(OS_ANDROID)
+ return PathService::Get(DIR_CACHE, path);
++#elif defined(__ANDROID__)
++ *path = FilePath("/data/local/tmp");
++ return true;
+ #else
+ *path = FilePath("/tmp");
+ return true;
+--- a/base/json/json_reader_unittest.cc
++++ b/base/json/json_reader_unittest.cc
+@@ -567,7 +567,7 @@ TEST(JSONReaderTest, Reading) {
+ }
+ }
+
+-TEST(JSONReaderTest, ReadFromFile) {
++TEST(JSONReaderTest, DISABLED_ReadFromFile) {
+ FilePath path;
+ ASSERT_TRUE(PathService::Get(base::DIR_TEST_DATA, &path));
+ path = path.AppendASCII("json");
+--- a/base/json/json_value_serializer_unittest.cc
++++ b/base/json/json_value_serializer_unittest.cc
+@@ -402,7 +402,7 @@ class JSONFileValueSerializerTest : publ
+ ScopedTempDir temp_dir_;
+ };
+
+-TEST_F(JSONFileValueSerializerTest, Roundtrip) {
++TEST_F(JSONFileValueSerializerTest, DISABLED_Roundtrip) {
+ FilePath original_file_path;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
+ original_file_path = original_file_path.AppendASCII("serializer_test.json");
+@@ -445,7 +445,7 @@ TEST_F(JSONFileValueSerializerTest, Roun
+ EXPECT_TRUE(DeleteFile(written_file_path, false));
+ }
+
+-TEST_F(JSONFileValueSerializerTest, RoundtripNested) {
++TEST_F(JSONFileValueSerializerTest, DISABLED_RoundtripNested) {
+ FilePath original_file_path;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &original_file_path));
+ original_file_path =
+@@ -471,7 +471,7 @@ TEST_F(JSONFileValueSerializerTest, Roun
+ EXPECT_TRUE(DeleteFile(written_file_path, false));
+ }
+
+-TEST_F(JSONFileValueSerializerTest, NoWhitespace) {
++TEST_F(JSONFileValueSerializerTest, DISABLED_NoWhitespace) {
+ FilePath source_file_path;
+ ASSERT_TRUE(PathService::Get(DIR_TEST_DATA, &source_file_path));
+ source_file_path =
diff --git a/libchrome_tools/patch/protobuf.patch b/libchrome_tools/patch/protobuf.patch
new file mode 100644
index 000000000..343da9c45
--- /dev/null
+++ b/libchrome_tools/patch/protobuf.patch
@@ -0,0 +1,4 @@
+--- /dev/null
++++ b/third_party/protobuf/src/google/protobuf/message_lite.h
+@@ -0,0 +1 @@
++#include <google/protobuf/message_lite.h>
diff --git a/libchrome_tools/patch/shared_memory_handle.patch b/libchrome_tools/patch/shared_memory_handle.patch
new file mode 100644
index 000000000..fb2efafe7
--- /dev/null
+++ b/libchrome_tools/patch/shared_memory_handle.patch
@@ -0,0 +1,22 @@
+diff --git a/base/memory/shared_memory_handle.h b/base/memory/shared_memory_handle.h
+index dd3d47a..7367188 100644
+--- a/base/memory/shared_memory_handle.h
++++ b/base/memory/shared_memory_handle.h
+@@ -146,7 +146,7 @@ class BASE_EXPORT SharedMemoryHandle {
+ int Release();
+ #endif
+
+-#if defined(OS_ANDROID)
++#if defined(OS_ANDROID) || defined(__ANDROID__)
+ // Marks the current file descriptor as read-only, for the purpose of
+ // mapping. This is independent of the region's read-only status.
+ void SetReadOnly() { read_only_ = true; }
+@@ -218,7 +218,7 @@ class BASE_EXPORT SharedMemoryHandle {
+ bool ownership_passes_to_ipc_ = false;
+ };
+ };
+-#elif defined(OS_ANDROID)
++#elif defined(OS_ANDROID) || defined(__ANDROID__)
+ friend class SharedMemory;
+
+ FileDescriptor file_descriptor_;
diff --git a/libchrome_tools/patch/shared_memory_mapping.patch b/libchrome_tools/patch/shared_memory_mapping.patch
new file mode 100644
index 000000000..f5362f0d5
--- /dev/null
+++ b/libchrome_tools/patch/shared_memory_mapping.patch
@@ -0,0 +1,33 @@
+diff --git a/base/memory/shared_memory_mapping.cc b/base/memory/shared_memory_mapping.cc
+index 005e3fc..2b42928 100644
+--- a/base/memory/shared_memory_mapping.cc
++++ b/base/memory/shared_memory_mapping.cc
+@@ -7,7 +7,8 @@
+ #include <utility>
+
+ #include "base/logging.h"
+-#include "base/memory/shared_memory_tracker.h"
++// Unsupported in libchrome
++// #include "base/memory/shared_memory_tracker.h"
+ #include "base/unguessable_token.h"
+ #include "build/build_config.h"
+
+@@ -62,14 +63,15 @@ SharedMemoryMapping::SharedMemoryMapping(void* memory,
+ size_t mapped_size,
+ const UnguessableToken& guid)
+ : memory_(memory), size_(size), mapped_size_(mapped_size), guid_(guid) {
+- SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
++ // Unsupported in libchrome.
++ // SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
+ }
+
+ void SharedMemoryMapping::Unmap() {
+ if (!IsValid())
+ return;
+-
+- SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
++ // Unsupported in libchrome.
++ // SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
+ #if defined(OS_WIN)
+ if (!UnmapViewOfFile(memory_))
+ DPLOG(ERROR) << "UnmapViewOfFile";
diff --git a/libchrome_tools/patch/shared_memory_posix.patch b/libchrome_tools/patch/shared_memory_posix.patch
new file mode 100644
index 000000000..169bbc8fb
--- /dev/null
+++ b/libchrome_tools/patch/shared_memory_posix.patch
@@ -0,0 +1,90 @@
+diff --git a/base/memory/shared_memory_posix.cc b/base/memory/shared_memory_posix.cc
+index e1289e7e1da0..aa718957cf26 100644
+--- a/base/memory/shared_memory_posix.cc
++++ b/base/memory/shared_memory_posix.cc
+@@ -29,6 +30,8 @@
+
+ #if defined(OS_ANDROID)
+ #include "base/os_compat_android.h"
++#endif
++#if defined(OS_ANDROID) || defined(__ANDROID__)
+ #include "third_party/ashmem/ashmem.h"
+ #endif
+
+@@ -80,7 +83,7 @@ bool SharedMemory::CreateAndMapAnonymous(size_t size) {
+ return CreateAnonymous(size) && Map(size);
+ }
+
+-#if !defined(OS_ANDROID)
++#if !defined(OS_ANDROID) && !defined(__ANDROID__)
+
+ // Chromium mostly only uses the unique/private shmem as specified by
+ // "name == L"". The exception is in the StatsTable.
+@@ -252,7 +255,7 @@ bool SharedMemory::Open(const std::string& name, bool read_only) {
+ FileDescriptor(readonly_mapped_file, false), 0, shm_.GetGUID());
+ return result;
+ }
+-#endif // !defined(OS_ANDROID)
++#endif // !defined(OS_ANDROID) && !defined(__ANDROID__)
+
+ bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+ if (!shm_.IsValid())
+@@ -264,7 +267,7 @@ bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+ if (memory_)
+ return false;
+
+-#if defined(OS_ANDROID)
++#if defined(OS_ANDROID) || defined(__ANDROID__)
+ // On Android, Map can be called with a size and offset of zero to use the
+ // ashmem-determined size.
+ if (bytes == 0) {
+@@ -277,19 +280,19 @@ bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+
+ // Sanity check. This shall catch invalid uses of the SharedMemory APIs
+ // but will not protect against direct mmap() attempts.
+- if (shm_.IsReadOnly()) {
+- // Use a DCHECK() to call writable mappings with read-only descriptors
+- // in debug builds immediately. Return an error for release builds
+- // or during unit-testing (assuming a ScopedLogAssertHandler was installed).
+- DCHECK(read_only_)
+- << "Trying to map a region writable with a read-only descriptor.";
+- if (!read_only_) {
+- return false;
+- }
+- if (!shm_.SetRegionReadOnly()) { // Ensure the region is read-only.
+- return false;
+- }
+- }
++ // if (shm_.IsReadOnly()) {
++ // // Use a DCHECK() to call writable mappings with read-only descriptors
++ // // in debug builds immediately. Return an error for release builds
++ // // or during unit-testing (assuming a ScopedLogAssertHandler was installed).
++ // DCHECK(read_only_)
++ // << "Trying to map a region writable with a read-only descriptor.";
++ // if (!read_only_) {
++ // return false;
++ // }
++ // if (!shm_.SetRegionReadOnly()) { // Ensure the region is read-only.
++ // return false;
++ // }
++ // }
+ #endif
+
+ memory_ = mmap(nullptr, bytes, PROT_READ | (read_only_ ? 0 : PROT_WRITE),
+@@ -334,7 +339,7 @@ SharedMemoryHandle SharedMemory::TakeHandle() {
+ return handle_copy;
+ }
+
+-#if !defined(OS_ANDROID)
++#if !defined(OS_ANDROID) && !defined(__ANDROID__)
+ void SharedMemory::Close() {
+ if (shm_.IsValid()) {
+ shm_.Close();
+@@ -374,6 +379,6 @@ SharedMemoryHandle SharedMemory::GetReadOnlyHandle() const {
+ CHECK(readonly_shm_.IsValid());
+ return readonly_shm_.Duplicate();
+ }
+-#endif // !defined(OS_ANDROID)
++#endif // !defined(OS_ANDROID) && !defined(__ANDROID__)
+
+ } // namespace base
diff --git a/libchrome_tools/patch/ssl.patch b/libchrome_tools/patch/ssl.patch
new file mode 100644
index 000000000..d502081e0
--- /dev/null
+++ b/libchrome_tools/patch/ssl.patch
@@ -0,0 +1,82 @@
+# Chrome asumes boringssl, while system installed ssl library may not.
+
+--- a/crypto/openssl_util.cc
++++ b/crypto/openssl_util.cc
+@@ -4,6 +4,13 @@
+
+ #include "crypto/openssl_util.h"
+
++#if defined(OPENSSL_IS_BORINGSSL)
++#include <openssl/cpu.h>
++#else
++#include <openssl/ssl.h>
++#endif
++#include <openssl/crypto.h>
++#include <openssl/err.h>
+ #include <stddef.h>
+ #include <stdint.h>
+
+@@ -11,8 +18,6 @@
+
+ #include "base/logging.h"
+ #include "base/strings/string_piece.h"
+-#include "third_party/boringssl/src/include/openssl/crypto.h"
+-#include "third_party/boringssl/src/include/openssl/err.h"
+
+ namespace crypto {
+
+@@ -35,8 +40,12 @@ int OpenSSLErrorCallback(const char* str
+ } // namespace
+
+ void EnsureOpenSSLInit() {
++#if defined(OPENSSL_IS_BORINGSSL)
+ // CRYPTO_library_init may be safely called concurrently.
+ CRYPTO_library_init();
++#else
++ SSL_library_init();
++#endif
+ }
+
+ void ClearOpenSSLERRStack(const tracked_objects::Location& location) {
+--- a/crypto/rsa_private_key.h
++++ b/crypto/rsa_private_key.h
+@@ -7,6 +7,7 @@
+
+ #include <stddef.h>
+ #include <stdint.h>
++#include <openssl/base.h>
+
+ #include <memory>
+ #include <vector>
+@@ -14,7 +15,6 @@
+ #include "base/macros.h"
+ #include "build/build_config.h"
+ #include "crypto/crypto_export.h"
+-#include "third_party/boringssl/src/include/openssl/base.h"
+
+ namespace crypto {
+
+--- a/crypto/secure_hash.cc
++++ b/crypto/secure_hash.cc
+@@ -4,14 +4,18 @@
+
+ #include "crypto/secure_hash.h"
+
++#if defined(OPENSSL_IS_BORINGSSL)
++#include <openssl/mem.h>
++#else
++#include <openssl/crypto.h>
++#endif
++#include <openssl/sha.h>
+ #include <stddef.h>
+
+ #include "base/logging.h"
+ #include "base/memory/ptr_util.h"
+ #include "base/pickle.h"
+ #include "crypto/openssl_util.h"
+-#include "third_party/boringssl/src/include/openssl/mem.h"
+-#include "third_party/boringssl/src/include/openssl/sha.h"
+
+ namespace crypto {
+
+
diff --git a/libchrome_tools/patch/statfs_f_type.patch b/libchrome_tools/patch/statfs_f_type.patch
new file mode 100644
index 000000000..f4b8df4dd
--- /dev/null
+++ b/libchrome_tools/patch/statfs_f_type.patch
@@ -0,0 +1,40 @@
+# In some platforms, |statfs_buf.f_type| is declared as signed, but some of the
+# values will overflow it, causing narrowing warnings. Cast to the largest
+# possible unsigned integer type to avoid it.
+
+--- a/base/files/file_util_linux.cc
++++ b/base/files/file_util_linux.cc
+@@ -6,6 +6,7 @@
+
+ #include <errno.h>
+ #include <linux/magic.h>
++#include <stdint.h>
+ #include <sys/vfs.h>
+
+ #include "base/files/file_path.h"
+@@ -23,7 +24,10 @@ bool GetFileSystemType(const FilePath& p
+
+ // Not all possible |statfs_buf.f_type| values are in linux/magic.h.
+ // Missing values are copied from the statfs man page.
+- switch (statfs_buf.f_type) {
++ // In some platforms, |statfs_buf.f_type| is declared as signed, but some of
++ // the values will overflow it, causing narrowing warnings. Cast to the
++ // largest possible unsigned integer type to avoid it.
++ switch (static_cast<uintmax_t>(statfs_buf.f_type)) {
+ case 0:
+ *type = FILE_SYSTEM_0;
+ break;
+--- a/base/sys_info_posix.cc
++++ b/base/sys_info_posix.cc
+@@ -90,7 +90,10 @@ bool IsStatsZeroIfUnlimited(const base::FilePath& path) {
+ if (HANDLE_EINTR(statfs(path.value().c_str(), &stats)) != 0)
+ return false;
+
+- switch (stats.f_type) {
++ // In some platforms, |statfs_buf.f_type| is declared as signed, but some of
++ // the values will overflow it, causing narrowing warnings. Cast to the
++ // largest possible unsigned integer type to avoid it.
++ switch (static_cast<uintmax_t>(stats.f_type)) {
+ case TMPFS_MAGIC:
+ case HUGETLBFS_MAGIC:
+ case RAMFS_MAGIC:
diff --git a/libchrome_tools/patch/subprocess.patch b/libchrome_tools/patch/subprocess.patch
new file mode 100644
index 000000000..bbd819ff4
--- /dev/null
+++ b/libchrome_tools/patch/subprocess.patch
@@ -0,0 +1,74 @@
+--- a/base/process/process_metrics_unittest.cc
++++ b/base/process/process_metrics_unittest.cc
+@@ -569,6 +569,9 @@ MULTIPROCESS_TEST_MAIN(ChildMain) {
+
+ } // namespace
+
++// ARC note: don't compile as SpawnMultiProcessTestChild brings in a lot of
++// extra dependency.
++#if !defined(OS_ANDROID) && !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+ TEST(ProcessMetricsTest, GetChildOpenFdCount) {
+ ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+@@ -582,9 +585,23 @@ TEST(ProcessMetricsTest, GetChildOpenFdCount) {
+
+ std::unique_ptr<ProcessMetrics> metrics(
+ ProcessMetrics::CreateProcessMetrics(child.Handle()));
+- EXPECT_EQ(0, metrics->GetOpenFdCount());
++ // Try a couple times to observe the child with 0 fds open.
++ // Sometimes we've seen that the child can have 1 remaining
++ // fd shortly after receiving the signal. Potentially this
++ // is actually the signal file still open in the child.
++ int open_fds = -1;
++ for (int tries = 0; tries < 5; ++tries) {
++ open_fds = metrics->GetOpenFdCount();
++ if (!open_fds) {
++ break;
++ }
++ PlatformThread::Sleep(TimeDelta::FromMilliseconds(1));
++ }
++ EXPECT_EQ(0, open_fds);
+ ASSERT_TRUE(child.Terminate(0, true));
+ }
++#endif // !defined(__ANDROID__)
++
+ #endif // defined(OS_LINUX)
+
+ #if defined(OS_ANDROID) || defined(OS_LINUX)
+--- a/base/test/multiprocess_test.cc
++++ b/base/test/multiprocess_test.cc
+@@ -13,7 +13,7 @@
+
+ namespace base {
+
+-#if !defined(OS_ANDROID)
++#if !defined(OS_ANDROID) && !defined(__ANDROID__) && !defined(__ANDROID_HOST__)
+ Process SpawnMultiProcessTestChild(const std::string& procname,
+ const CommandLine& base_command_line,
+ const LaunchOptions& options) {
+@@ -39,7 +39,7 @@ bool TerminateMultiProcessTestChild(const Process& process,
+ return process.Terminate(exit_code, wait);
+ }
+
+-#endif // !defined(OS_ANDROID)
++#endif // !OS_ANDROID && !__ANDROID__ && !__ANDROID_HOST__
+
+ CommandLine GetMultiProcessTestChildBaseCommandLine() {
+ base::ScopedAllowBlockingForTesting allow_blocking;
+@@ -52,6 +52,8 @@ CommandLine GetMultiProcessTestChildBaseCommandLine() {
+
+ MultiProcessTest::MultiProcessTest() = default;
+
++// Don't compile on ARC.
++#if 0
+ Process MultiProcessTest::SpawnChild(const std::string& procname) {
+ LaunchOptions options;
+ #if defined(OS_WIN)
+@@ -64,6 +66,7 @@ Process MultiProcessTest::SpawnChildWithOptions(const std::string& procname,
+ const LaunchOptions& options) {
+ return SpawnMultiProcessTestChild(procname, MakeCmdLine(procname), options);
+ }
++#endif
+
+ CommandLine MultiProcessTest::MakeCmdLine(const std::string& procname) {
+ CommandLine command_line = GetMultiProcessTestChildBaseCommandLine();
diff --git a/libchrome_tools/patch/symbolize.patch b/libchrome_tools/patch/symbolize.patch
new file mode 100644
index 000000000..a7eeda516
--- /dev/null
+++ b/libchrome_tools/patch/symbolize.patch
@@ -0,0 +1,18 @@
+--- /dev/null
++++ b/base/third_party/symbolize/symbolize.h
+@@ -0,0 +1,15 @@
++// Copyright (C) 2018 The Android Open Source Project
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++
++#error "symbolize support was removed from libchrome"
diff --git a/libchrome_tools/patch/task_annotator.patch b/libchrome_tools/patch/task_annotator.patch
new file mode 100644
index 000000000..52d21c6e7
--- /dev/null
+++ b/libchrome_tools/patch/task_annotator.patch
@@ -0,0 +1,12 @@
+diff --git a/base/debug/task_annotator.h b/base/debug/task_annotator.h
+index fedca7d..9ff5c7b 100644
+--- a/base/debug/task_annotator.h
++++ b/base/debug/task_annotator.h
+@@ -20,6 +20,7 @@ class BASE_EXPORT TaskAnnotator {
+ public:
+ class ObserverForTesting {
+ public:
++ virtual ~ObserverForTesting() = default;
+ // Invoked just before RunTask() in the scope in which the task is about to
+ // be executed.
+ virtual void BeforeRunTask(const PendingTask* pending_task) = 0;
diff --git a/libchrome_tools/patch/trace_event.patch b/libchrome_tools/patch/trace_event.patch
new file mode 100644
index 000000000..43dc0524f
--- /dev/null
+++ b/libchrome_tools/patch/trace_event.patch
@@ -0,0 +1,191 @@
+--- a/base/trace_event/trace_event.h
++++ b/base/trace_event/trace_event.h
+@@ -5,6 +5,43 @@
+ #ifndef BASE_TRACE_EVENT_TRACE_EVENT_H_
+ #define BASE_TRACE_EVENT_TRACE_EVENT_H_
+
++// Replace with stub implementation.
++#if 1
++#include "base/trace_event/common/trace_event_common.h"
++#include "base/trace_event/heap_profiler.h"
++
++// To avoid -Wunused-* errors, eat expression by macro.
++namespace libchrome_internal {
++template <typename... Args> void Ignore(Args&&... args) {}
++}
++#define INTERNAL_IGNORE(...) \
++ (false ? libchrome_internal::Ignore(__VA_ARGS__) : (void) 0)
++
++// Body is effectively empty.
++#define INTERNAL_TRACE_EVENT_ADD_SCOPED(...) INTERNAL_IGNORE(__VA_ARGS__)
++#define INTERNAL_TRACE_TASK_EXECUTION(...)
++#define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
++ INTERNAL_IGNORE(__VA_ARGS__)
++#define TRACE_ID_MANGLE(val) (val)
++
++namespace base {
++namespace trace_event {
++
++class TraceLog {
++ public:
++ static TraceLog* GetInstance() {
++ static TraceLog instance;
++ return &instance;
++ }
++
++ pid_t process_id() { return 0; }
++ void SetCurrentThreadBlocksMessageLoop() {}
++};
++
++} // namespace trace_event
++} // namespace base
++#else
++
+ // This header file defines implementation details of how the trace macros in
+ // trace_event_common.h collect and store trace events. Anything not
+ // implementation-specific should go in trace_event_common.h instead of here.
+@@ -1115,4 +1152,5 @@ template<typename IDType> class TraceSco
+ } // namespace trace_event
+ } // namespace base
+
++#endif
+ #endif // BASE_TRACE_EVENT_TRACE_EVENT_H_
+--- a/base/trace_event/heap_profiler.h
++++ b/base/trace_event/heap_profiler.h
+@@ -5,6 +5,22 @@
+ #ifndef BASE_TRACE_EVENT_HEAP_PROFILER_H
+ #define BASE_TRACE_EVENT_HEAP_PROFILER_H
+
++// Replace with stub implementation.
++#if 1
++#define TRACE_HEAP_PROFILER_API_SCOPED_TASK_EXECUTION \
++ trace_event_internal::HeapProfilerScopedTaskExecutionTracker
++
++namespace trace_event_internal {
++
++class HeapProfilerScopedTaskExecutionTracker {
++ public:
++ explicit HeapProfilerScopedTaskExecutionTracker(const char*) {}
++};
++
++} // namespace trace_event_internal
++
++#else
++
+ #include "base/compiler_specific.h"
+ #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+@@ -86,4 +102,5 @@ class BASE_EXPORT HeapProfilerScopedIgno
+
+ } // namespace trace_event_internal
+
++#endif
+ #endif // BASE_TRACE_EVENT_HEAP_PROFILER_H
+--- a/base/test/test_pending_task.h
++++ b/base/test/test_pending_task.h
+@@ -10,7 +10,8 @@
+ #include "base/callback.h"
+ #include "base/location.h"
+ #include "base/time/time.h"
+-#include "base/trace_event/trace_event_argument.h"
++// Unsupported in libchrome.
++// #include "base/trace_event/trace_event_argument.h"
+
+ namespace base {
+
+@@ -58,10 +59,13 @@ struct TestPendingTask {
+ TimeDelta delay;
+ TestNestability nestability;
+
++// Unsupported in libchrome.
++#if 0
+ // Functions for using test pending task with tracing, useful in unit
+ // testing.
+ void AsValueInto(base::trace_event::TracedValue* state) const;
+ std::unique_ptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
++#endif
+ std::string ToString() const;
+
+ private:
+--- a/base/test/test_pending_task.cc
++++ b/base/test/test_pending_task.cc
+@@ -38,6 +38,8 @@ bool TestPendingTask::ShouldRunBefore(co
+
+ TestPendingTask::~TestPendingTask() {}
+
++// Unsupported in libchrome.
++#if 0
+ void TestPendingTask::AsValueInto(base::trace_event::TracedValue* state) const {
+ state->SetInteger("run_at", GetTimeToRun().ToInternalValue());
+ state->SetString("posting_function", location.ToString());
+@@ -61,10 +63,14 @@ TestPendingTask::AsValue() const {
+ AsValueInto(state.get());
+ return std::move(state);
+ }
++#endif
+
+ std::string TestPendingTask::ToString() const {
+ std::string output("TestPendingTask(");
++// Unsupported in libchrome.
++#if 0
+ AsValue()->AppendAsTraceFormat(&output);
++#endif
+ output += ")";
+ return output;
+ }
+---- a/base/threading/thread_id_name_manager.cc
++++ b/base/threading/thread_id_name_manager.cc
+@@ -12,7 +12,8 @@
+ #include "base/no_destructor.h"
+ #include "base/strings/string_util.h"
+ #include "base/threading/thread_local.h"
+-#include "base/trace_event/heap_profiler_allocation_context_tracker.h"
++// Unsupported in libchrome.
++// #include "base/trace_event/heap_profiler_allocation_context_tracker.h"
+
+ namespace base {
+ namespace {
+@@ -94,8 +95,9 @@ void ThreadIdNameManager::SetName(const std::string& name) {
+ // call GetName(which holds a lock) during the first allocation because it can
+ // cause a deadlock when the first allocation happens in the
+ // ThreadIdNameManager itself when holding the lock.
+- trace_event::AllocationContextTracker::SetCurrentThreadName(
+- leaked_str->c_str());
++ // Unsupported in libchrome.
++ // trace_event::AllocationContextTracker::SetCurrentThreadName(
++ // leaked_str->c_str());
+ }
+
+ const char* ThreadIdNameManager::GetName(PlatformThreadId id) {
+--- a/base/memory/shared_memory_posix.cc
++++ b/base/memory/shared_memory_posix.cc
+@@ -16,7 +16,8 @@
+ #include "base/logging.h"
+ #include "base/macros.h"
+ #include "base/memory/shared_memory_helper.h"
+-#include "base/memory/shared_memory_tracker.h"
++// Unsupported in libchrome.
++// #include "base/memory/shared_memory_tracker.h"
+ #include "base/posix/eintr_wrapper.h"
+ #include "base/posix/safe_strerror.h"
+ #include "base/process/process_metrics.h"
+@@ -302,7 +305,8 @@ bool SharedMemory::MapAt(off_t offset, size_t bytes) {
+ DCHECK_EQ(0U,
+ reinterpret_cast<uintptr_t>(memory_) &
+ (SharedMemory::MAP_MINIMUM_ALIGNMENT - 1));
+- SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
++ // Unsupported in libchrome.
++ // SharedMemoryTracker::GetInstance()->IncrementMemoryUsage(*this);
+ } else {
+ memory_ = nullptr;
+ }
+@@ -314,7 +318,8 @@ bool SharedMemory::Unmap() {
+ if (!memory_)
+ return false;
+
+- SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
++ // Unsupported in libchrome.
++ // SharedMemoryTracker::GetInstance()->DecrementMemoryUsage(*this);
+ munmap(memory_, mapped_size_);
+ memory_ = nullptr;
+ mapped_size_ = 0;
diff --git a/libchrome_tools/patch/values.patch b/libchrome_tools/patch/values.patch
new file mode 100644
index 000000000..7e36b490c
--- /dev/null
+++ b/libchrome_tools/patch/values.patch
@@ -0,0 +1,63 @@
+# we don't support trace_event on libchrome
+
+--- a/base/values.cc
++++ b/base/values.cc
+@@ -18,7 +18,8 @@
+ #include "base/stl_util.h"
+ #include "base/strings/string_util.h"
+ #include "base/strings/utf_string_conversions.h"
+-#include "base/trace_event/memory_usage_estimator.h"
++// Unsupported in libchrome
++// #include "base/trace_event/memory_usage_estimator.h"
+
+ namespace base {
+
+@@ -632,20 +633,21 @@ bool Value::Equals(const Value* other) const {
+ return *this == *other;
+ }
+
+-size_t Value::EstimateMemoryUsage() const {
+- switch (type_) {
+- case Type::STRING:
+- return base::trace_event::EstimateMemoryUsage(string_value_);
+- case Type::BINARY:
+- return base::trace_event::EstimateMemoryUsage(binary_value_);
+- case Type::DICTIONARY:
+- return base::trace_event::EstimateMemoryUsage(dict_);
+- case Type::LIST:
+- return base::trace_event::EstimateMemoryUsage(list_);
+- default:
+- return 0;
+- }
+-}
++// Unsupported in libchrome
++// size_t Value::EstimateMemoryUsage() const {
++// switch (type_) {
++// case Type::STRING:
++// return base::trace_event::EstimateMemoryUsage(string_value_);
++// case Type::BINARY:
++// return base::trace_event::EstimateMemoryUsage(binary_value_);
++// case Type::DICTIONARY:
++// return base::trace_event::EstimateMemoryUsage(dict_);
++// case Type::LIST:
++// return base::trace_event::EstimateMemoryUsage(list_);
++// default:
++// return 0;
++// }
++// }
+
+ void Value::InternalMoveConstructFrom(Value&& that) {
+ type_ = that.type_;
+
+--- a/base/values.h
++++ b/base/values.h
+@@ -352,7 +352,7 @@ class BASE_EXPORT Value {
+
+ // Estimates dynamic memory usage.
+ // See base/trace_event/memory_usage_estimator.h for more info.
+- size_t EstimateMemoryUsage() const;
++ // size_t EstimateMemoryUsage() const;
+
+ protected:
+ // TODO(crbug.com/646113): Make these private once DictionaryValue and
+
diff --git a/libchrome_tools/patch/virtual_destructor.patch b/libchrome_tools/patch/virtual_destructor.patch
new file mode 100644
index 000000000..64111333e
--- /dev/null
+++ b/libchrome_tools/patch/virtual_destructor.patch
@@ -0,0 +1,78 @@
+--- a/base/metrics/histogram.cc
++++ b/base/metrics/histogram.cc
+@@ -94,6 +94,7 @@ class Histogram::Factory {
+ uint32_t bucket_count,
+ int32_t flags)
+ : Factory(name, HISTOGRAM, minimum, maximum, bucket_count, flags) {}
++ virtual ~Factory() = default;
+
+ // Create histogram based on construction parameters. Caller takes
+ // ownership of the returned object.
+@@ -741,6 +742,7 @@ class LinearHistogram::Factory : public
+ bucket_count, flags) {
+ descriptions_ = descriptions;
+ }
++ ~Factory() override = default;
+
+ protected:
+ BucketRanges* CreateRanges() override {
+@@ -932,6 +934,7 @@ class BooleanHistogram::Factory : public
+ public:
+ Factory(const std::string& name, int32_t flags)
+ : Histogram::Factory(name, BOOLEAN_HISTOGRAM, 1, 2, 3, flags) {}
++ ~Factory() override = default;
+
+ protected:
+ BucketRanges* CreateRanges() override {
+@@ -1020,6 +1023,7 @@ class CustomHistogram::Factory : public
+ : Histogram::Factory(name, CUSTOM_HISTOGRAM, 0, 0, 0, flags) {
+ custom_ranges_ = custom_ranges;
+ }
++ ~Factory() override = default;
+
+ protected:
+ BucketRanges* CreateRanges() override {
+--- a/base/metrics/statistics_recorder.h
++++ b/base/metrics/statistics_recorder.h
+@@ -67,6 +67,7 @@ class BASE_EXPORT StatisticsRecorder {
+ // histograms from providers when necessary.
+ class HistogramProvider {
+ public:
++ virtual ~HistogramProvider() {}
+ // Merges all histogram information into the global versions.
+ virtual void MergeHistogramDeltas() = 0;
+ };
+--- a/base/bind_unittest.cc
++++ b/base/bind_unittest.cc
+@@ -69,6 +69,7 @@ static const int kChildValue = 2;
+
+ class Parent {
+ public:
++ virtual ~Parent() {}
+ void AddRef() const {}
+ void Release() const {}
+ virtual void VirtualSet() { value = kParentValue; }
+@@ -78,18 +79,23 @@ class Parent {
+
+ class Child : public Parent {
+ public:
++ ~Child() override {}
+ void VirtualSet() override { value = kChildValue; }
+ void NonVirtualSet() { value = kChildValue; }
+ };
+
+ class NoRefParent {
+ public:
++ virtual ~NoRefParent() {}
+ virtual void VirtualSet() { value = kParentValue; }
+ void NonVirtualSet() { value = kParentValue; }
+ int value;
+ };
+
+ class NoRefChild : public NoRefParent {
++ public:
++ ~NoRefChild() override {}
++ private:
+ void VirtualSet() override { value = kChildValue; }
+ void NonVirtualSet() { value = kChildValue; }
+ };
diff --git a/libchrome_tools/patches/Add-base-NoDestructor-T.patch b/libchrome_tools/patches/Add-base-NoDestructor-T.patch
new file mode 100644
index 000000000..9c95d4bc0
--- /dev/null
+++ b/libchrome_tools/patches/Add-base-NoDestructor-T.patch
@@ -0,0 +1,129 @@
+From c334673e96ce73cbf1a693c7c85b1450fcd3571c Mon Sep 17 00:00:00 2001
+From: Ben Chan <benchan@chromium.org>
+Date: Fri, 2 Nov 2018 23:07:01 -0700
+Subject: [PATCH] libchrome: add base::NoDestructor<T>
+
+CL:869351 introduces base::NoDestructor<T>, which is preferred in new
+code as a drop-in replacement for a function scoped static T* or T& that
+is dynamically initialized, and a global base::LazyInstance<T>.
+
+This CL patches libchrome to pull in base/no_destructor.h at r599267, so
+that we can migrate existing Chrome OS code to use base::NoDestructor<T>
+before the next libchrome uprev.
+
+BUG=None
+TEST=`emerge-$BOARD librchrome`
+
+Change-Id: I791a70e10da6318ea81eaaec869ba4702361289e
+---
+ base/no_destructor.h | 98 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 98 insertions(+)
+ create mode 100644 base/no_destructor.h
+
+diff --git base/no_destructor.h base/no_destructor.h
+new file mode 100644
+index 0000000..21cfef8
+--- /dev/null
++++ base/no_destructor.h
+@@ -0,0 +1,98 @@
++// Copyright 2018 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_NO_DESTRUCTOR_H_
++#define BASE_NO_DESTRUCTOR_H_
++
++#include <new>
++#include <utility>
++
++namespace base {
++
++// A wrapper that makes it easy to create an object of type T with static
++// storage duration that:
++// - is only constructed on first access
++// - never invokes the destructor
++// in order to satisfy the styleguide ban on global constructors and
++// destructors.
++//
++// Runtime constant example:
++// const std::string& GetLineSeparator() {
++// // Forwards to std::string(size_t, char, const Allocator&) constructor.
++// static const base::NoDestructor<std::string> s(5, '-');
++// return *s;
++// }
++//
++// More complex initialization with a lambda:
++// const std::string& GetSessionNonce() {
++// static const base::NoDestructor<std::string> nonce([] {
++// std::string s(16);
++// crypto::RandString(s.data(), s.size());
++// return s;
++// }());
++// return *nonce;
++// }
++//
++// NoDestructor<T> stores the object inline, so it also avoids a pointer
++// indirection and a malloc. Also note that since C++11 static local variable
++// initialization is thread-safe and so is this pattern. Code should prefer to
++// use NoDestructor<T> over:
++// - A function scoped static T* or T& that is dynamically initialized.
++// - A global base::LazyInstance<T>.
++//
++// Note that since the destructor is never run, this *will* leak memory if used
++// as a stack or member variable. Furthermore, a NoDestructor<T> should never
++// have global scope as that may require a static initializer.
++template <typename T>
++class NoDestructor {
++ public:
++ // Not constexpr; just write static constexpr T x = ...; if the value should
++ // be a constexpr.
++ template <typename... Args>
++ explicit NoDestructor(Args&&... args) {
++ new (storage_) T(std::forward<Args>(args)...);
++ }
++
++ // Allows copy and move construction of the contained type, to allow
++ // construction from an initializer list, e.g. for std::vector.
++ explicit NoDestructor(const T& x) { new (storage_) T(x); }
++ explicit NoDestructor(T&& x) { new (storage_) T(std::move(x)); }
++
++ NoDestructor(const NoDestructor&) = delete;
++ NoDestructor& operator=(const NoDestructor&) = delete;
++
++ ~NoDestructor() = default;
++
++ const T& operator*() const { return *get(); }
++ T& operator*() { return *get(); }
++
++ const T* operator->() const { return get(); }
++ T* operator->() { return get(); }
++
++ const T* get() const { return reinterpret_cast<const T*>(storage_); }
++ T* get() { return reinterpret_cast<T*>(storage_); }
++
++ private:
++ alignas(T) char storage_[sizeof(T)];
++
++#if defined(LEAK_SANITIZER)
++ // TODO(https://crbug.com/812277): This is a hack to work around the fact
++ // that LSan doesn't seem to treat NoDestructor as a root for reachability
++ // analysis. This means that code like this:
++ // static base::NoDestructor<std::vector<int>> v({1, 2, 3});
++ // is considered a leak. Using the standard leak sanitizer annotations to
++ // suppress leaks doesn't work: std::vector is implicitly constructed before
++ // calling the base::NoDestructor constructor.
++ //
++ // Unfortunately, I haven't been able to demonstrate this issue in simpler
++ // reproductions: until that's resolved, hold an explicit pointer to the
++ // placement-new'd object in leak sanitizer mode to help LSan realize that
++ // objects allocated by the contained type are still reachable.
++ T* storage_ptr_ = reinterpret_cast<T*>(storage_);
++#endif // defined(LEAK_SANITIZER)
++};
++
++} // namespace base
++
++#endif // BASE_NO_DESTRUCTOR_H_
+--
+2.19.1.930.g4563a0d9d0-goog
+
diff --git a/libchrome_tools/patches/Add-header-files-base-check_op-notreached-h.patch b/libchrome_tools/patches/Add-header-files-base-check_op-notreached-h.patch
new file mode 100644
index 000000000..8b61fa4d8
--- /dev/null
+++ b/libchrome_tools/patches/Add-header-files-base-check_op-notreached-h.patch
@@ -0,0 +1,48 @@
+From b69366c4a2f08545bd03e1c0aa6a37562510a2e6 Mon Sep 17 00:00:00 2001
+From: hscham <hscham@chromium.org>
+Date: Wed, 3 Jun 2020 17:26:49 +0900
+Subject: [PATCH] Add header files base/{check_op,notreached}.h
+
+Change-Id: I5267ddeba3a63c7977f093b1a25dff760dbe167b
+---
+ base/check_op.h | 10 ++++++++++
+ base/notreached.h | 10 ++++++++++
+ 2 files changed, 20 insertions(+)
+ create mode 100644 base/check_op.h
+ create mode 100644 base/notreached.h
+
+diff --git a/base/check_op.h b/base/check_op.h
+new file mode 100644
+index 000000000..caa3c3af6
+--- /dev/null
++++ base/check_op.h
+@@ -0,0 +1,10 @@
++// Copyright 2020 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_CHECK_OP_H_
++#define BASE_CHECK_OP_H_
++
++#include "base/logging.h"
++
++#endif // BASE_CHECK_OP_H_
+diff --git a/base/notreached.h b/base/notreached.h
+new file mode 100644
+index 000000000..1eacc44e4
+--- /dev/null
++++ base/notreached.h
+@@ -0,0 +1,10 @@
++// Copyright 2020 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_NOTREACHED_H_
++#define BASE_NOTREACHED_H_
++
++#include "base/logging.h"
++
++#endif // BASE_NOTREACHED_H_
+--
+2.27.0.rc2.251.g90737beb825-goog
+
diff --git a/libchrome_tools/patches/Connect-to-NameOwnerChanged-signal-when-setting-call.patch b/libchrome_tools/patches/Connect-to-NameOwnerChanged-signal-when-setting-call.patch
new file mode 100644
index 000000000..83d2e49e9
--- /dev/null
+++ b/libchrome_tools/patches/Connect-to-NameOwnerChanged-signal-when-setting-call.patch
@@ -0,0 +1,163 @@
+From c2e55024c6a03dcb099270718e70139542d8b0e4 Mon Sep 17 00:00:00 2001
+From: Bing Xue <bingxue@google.com>
+Date: Thu, 1 Aug 2019 15:47:10 -0700
+Subject: [PATCH] Connect to NameOwnerChanged signal when setting callback
+
+In ObjectManager, when ConnectToNameOwnerChangedSignal is called the first time,
+we could have already missed the NameOwnerChanged signal if we get a value from
+UpdateNameOwnerAndBlock. This means NameOwnerChanged callbacks will
+never be called until that service restarts. In ObjectManager we run
+into this problem:
+
+1. ObjectManager::SetupMatchRuleAndFilter is called, calling
+bus_->GetServiceOwnerAndBlock shows empty service name owner.
+
+2. ObjectManager::OnSetupManagerRuleAndFilterComplete callback will call
+object_proxy_->ConnectToSignal, which in turn calls
+ConnectToNameOwnerChangedSignal the first time. At this point,
+UpdateNameOwnerAndBlock calling bus_->GetServiceOwnerAndBlock returns the
+current name owner of the service, this means the NameOwnerChanged signal
+is already sent on system bus.
+
+3. As a result, ObjectManager::NameOwnerChanged is never called while
+the service is already online. This in turn causes GetManagedObject to
+never be called, and the object manager interface never added.
+
+See detailed sample logs in b/138416411.
+
+This CL adds the following:
+
+1. Make SetNameOwnerChangedCallback run
+ConnectToNameOwnerChangedSignal when called. Since ObjectManager calls
+SetNameOwnerChangedCallback before posting SetupMatchRuleAndFilter (in which
+ObjectManager attempts to get the service name owner through a blocking call),
+this removes the time gap described above that causes lost signal.
+
+2. Make dbus thread the only writer to |service_name_owner_|, given that
+connecting to the NameOwnerChanged signal right away in ObjectManager
+ctor causes potential data race in writing to |service_name_owner_| in
+both NameOwnerChanged (on origin thread) and SetupMatchRuleAndFilter (on
+dbus thread).
+
+BUG=b:138416411
+TEST=Manually on device.
+
+Change-Id: Ie95a5b7b303637acadebda151cc478e52b6a1af5
+---
+ dbus/object_manager.cc | 20 +++++++++++++++++---
+ dbus/object_manager.h | 5 +++++
+ dbus/object_proxy.cc | 13 +++++++++++++
+ dbus/object_proxy.h | 3 +++
+ 4 files changed, 38 insertions(+), 3 deletions(-)
+
+diff --git a/dbus/object_manager.cc b/dbus/object_manager.cc
+index 05d4b2ddeabd..44f120864310 100644
+--- a/dbus/object_manager.cc
++++ b/dbus/object_manager.cc
+@@ -187,8 +187,12 @@ bool ObjectManager::SetupMatchRuleAndFilter() {
+ if (!bus_->Connect() || !bus_->SetUpAsyncOperations())
+ return false;
+
+- service_name_owner_ =
+- bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
++ // Try to get |service_name_owner_| from dbus if we haven't received any
++ // NameOwnerChanged signals.
++ if (service_name_owner_.empty()) {
++ service_name_owner_ =
++ bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
++ }
+
+ const std::string match_rule =
+ base::StringPrintf(
+@@ -224,6 +228,7 @@ void ObjectManager::OnSetupMatchRuleAndFilterComplete(bool success) {
+ DCHECK(bus_);
+ DCHECK(object_proxy_);
+ DCHECK(setup_success_);
++ bus_->AssertOnOriginThread();
+
+ // |object_proxy_| is no longer valid if the Bus was shut down before this
+ // call. Don't initiate any other action from the origin thread.
+@@ -505,9 +510,18 @@ void ObjectManager::RemoveInterface(const ObjectPath& object_path,
+ }
+ }
+
++void ObjectManager::UpdateServiceNameOwner(const std::string& new_owner) {
++ bus_->AssertOnDBusThread();
++ service_name_owner_ = new_owner;
++}
++
+ void ObjectManager::NameOwnerChanged(const std::string& old_owner,
+ const std::string& new_owner) {
+- service_name_owner_ = new_owner;
++ bus_->AssertOnOriginThread();
++
++ bus_->GetDBusTaskRunner()->PostTask(
++ FROM_HERE,
++ base::BindOnce(&ObjectManager::UpdateServiceNameOwner, this, new_owner));
+
+ if (!old_owner.empty()) {
+ ObjectMap::iterator iter = object_map_.begin();
+diff --git a/dbus/object_manager.h b/dbus/object_manager.h
+index 05388de8e6eb..4b5fb790412d 100644
+--- a/dbus/object_manager.h
++++ b/dbus/object_manager.h
+@@ -317,6 +317,11 @@ class CHROME_DBUS_EXPORT ObjectManager final
+ void NameOwnerChanged(const std::string& old_owner,
+ const std::string& new_owner);
+
++ // Write |new_owner| to |service_name_owner_|. This method makes sure write
++ // happens on the DBus thread, which is the sole writer to
++ // |service_name_owner_|.
++ void UpdateServiceNameOwner(const std::string& new_owner);
++
+ Bus* bus_;
+ std::string service_name_;
+ std::string service_name_owner_;
+diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc
+index 7adf8f179471..de5785e98307 100644
+--- a/dbus/object_proxy.cc
++++ b/dbus/object_proxy.cc
+@@ -274,6 +274,10 @@ void ObjectProxy::SetNameOwnerChangedCallback(
+ bus_->AssertOnOriginThread();
+
+ name_owner_changed_callback_ = callback;
++
++ bus_->GetDBusTaskRunner()->PostTask(
++ FROM_HERE,
++ base::BindOnce(&ObjectProxy::TryConnectToNameOwnerChangedSignal, this));
+ }
+
+ void ObjectProxy::WaitForServiceToBeAvailable(
+@@ -458,6 +462,15 @@ bool ObjectProxy::ConnectToNameOwnerChangedSignal() {
+ return success;
+ }
+
++void ObjectProxy::TryConnectToNameOwnerChangedSignal() {
++ bus_->AssertOnDBusThread();
++
++ bool success = ConnectToNameOwnerChangedSignal();
++ LOG_IF(WARNING, !success)
++ << "Failed to connect to NameOwnerChanged signal for object: "
++ << object_path_.value();
++}
++
+ bool ObjectProxy::ConnectToSignalInternal(const std::string& interface_name,
+ const std::string& signal_name,
+ SignalCallback signal_callback) {
+diff --git a/dbus/object_proxy.h b/dbus/object_proxy.h
+index 22e44f1d64c0..b1bf622a12cb 100644
+--- a/dbus/object_proxy.h
++++ b/dbus/object_proxy.h
+@@ -267,6 +267,9 @@ class CHROME_DBUS_EXPORT ObjectProxy
+ // Connects to NameOwnerChanged signal.
+ bool ConnectToNameOwnerChangedSignal();
+
++ // Tries to connect to NameOwnerChanged signal, ignores any error.
++ void TryConnectToNameOwnerChangedSignal();
++
+ // Helper function for ConnectToSignal().
+ bool ConnectToSignalInternal(const std::string& interface_name,
+ const std::string& signal_name,
+--
+2.22.0.770.g0f2c4a37fd-goog
+
diff --git a/libchrome_tools/patches/Fix-TimeDelta.patch b/libchrome_tools/patches/Fix-TimeDelta.patch
new file mode 100644
index 000000000..65ab874a0
--- /dev/null
+++ b/libchrome_tools/patches/Fix-TimeDelta.patch
@@ -0,0 +1,164 @@
+commit db5f2b6e74d6d2e2a9c6f530199067c1d6eff7b6
+Author: Max Morin <maxmorin@chromium.org>
+Date: Mon Aug 27 09:45:24 2018 +0000
+
+ Make TimeDelta TriviallyCopyable for std::atomic.
+
+ We're having some awkwardness with working around the issue with stuff
+ like std::atomic<int64_t> and conversions back and forth. It would be
+ preferable to use std::atomic<TimeDelta> directly.
+
+ Removes the workaround added for bug 635974, since that was a bug in
+ vs 2015 and we use clang now.
+
+ Also fixes a couple of lint issues in time.h.
+
+ Bug: 635974, 851959, 761570
+ Change-Id: I4683f960b0c348748c5f0aaf222da4dda40256ec
+ Reviewed-on: https://chromium-review.googlesource.com/1184781
+ Commit-Queue: Max Morin <maxmorin@chromium.org>
+ Reviewed-by: Yuri Wiitala <miu@chromium.org>
+ Reviewed-by: Bruce Dawson <brucedawson@chromium.org>
+ Cr-Commit-Position: refs/heads/master@{#586219}
+
+diff --git a/base/time/time.h b/base/time/time.h
+index f4c2f93f30b4..7d4f308545c9 100644
+--- a/base/time/time.h
++++ b/base/time/time.h
+@@ -199,11 +199,6 @@ class BASE_EXPORT TimeDelta {
+ double InMicrosecondsF() const;
+ int64_t InNanoseconds() const;
+
+- constexpr TimeDelta& operator=(TimeDelta other) {
+- delta_ = other.delta_;
+- return *this;
+- }
+-
+ // Computations with other deltas. Can easily be made constexpr with C++17 but
+ // hard to do until then per limitations around
+ // __builtin_(add|sub)_overflow in safe_math_clang_gcc_impl.h :
+@@ -283,11 +278,6 @@ class BASE_EXPORT TimeDelta {
+ return delta_ >= other.delta_;
+ }
+
+-#if defined(OS_WIN)
+- // This works around crbug.com/635974
+- constexpr TimeDelta(const TimeDelta& other) : delta_(other.delta_) {}
+-#endif
+-
+ private:
+ friend int64_t time_internal::SaturatedAdd(TimeDelta delta, int64_t value);
+ friend int64_t time_internal::SaturatedSub(TimeDelta delta, int64_t value);
+@@ -375,7 +365,7 @@ class TimeBase {
+ //
+ // DEPRECATED - Do not use in new code. For serializing Time values, prefer
+ // Time::ToDeltaSinceWindowsEpoch().InMicroseconds(). http://crbug.com/634507
+- int64_t ToInternalValue() const { return us_; }
++ constexpr int64_t ToInternalValue() const { return us_; }
+
+ // The amount of time since the origin (or "zero") point. This is a syntactic
+ // convenience to aid in code readability, mainly for debugging/testing use
+@@ -799,7 +789,7 @@ constexpr TimeDelta TimeDelta::FromDouble(double value) {
+ // static
+ constexpr TimeDelta TimeDelta::FromProduct(int64_t value,
+ int64_t positive_value) {
+- DCHECK(positive_value > 0);
++ DCHECK(positive_value > 0); // NOLINT, DCHECK_GT isn't constexpr.
+ return value > std::numeric_limits<int64_t>::max() / positive_value
+ ? Max()
+ : value < std::numeric_limits<int64_t>::min() / positive_value
+@@ -903,8 +893,8 @@ class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
+ return TimeTicks(us);
+ }
+
+-#if defined(OS_WIN)
+ protected:
++#if defined(OS_WIN)
+ typedef DWORD (*TickFunctionType)(void);
+ static TickFunctionType SetMockTickFunction(TickFunctionType ticker);
+ #endif
+@@ -926,8 +916,7 @@ BASE_EXPORT std::ostream& operator<<(std::ostream& os, TimeTicks time_ticks);
+ // thread is running.
+ class BASE_EXPORT ThreadTicks : public time_internal::TimeBase<ThreadTicks> {
+ public:
+- ThreadTicks() : TimeBase(0) {
+- }
++ constexpr ThreadTicks() : TimeBase(0) {}
+
+ // Returns true if ThreadTicks::Now() is supported on this system.
+ static bool IsSupported() WARN_UNUSED_RESULT {
+diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
+index 5dc8888a3297..ce8cc39cbaec 100644
+--- a/base/time/time_unittest.cc
++++ b/base/time/time_unittest.cc
+@@ -1542,6 +1542,70 @@ TEST(TimeDelta, Overflows) {
+ EXPECT_EQ(kOneSecond, (ticks_now + kOneSecond) - ticks_now);
+ }
+
++constexpr TimeTicks TestTimeTicksConstexprCopyAssignment() {
++ TimeTicks a = TimeTicks::FromInternalValue(12345);
++ TimeTicks b;
++ b = a;
++ return b;
++}
++
++TEST(TimeTicks, ConstexprAndTriviallyCopiable) {
++ // "Trivially copyable" is necessary for use in std::atomic<TimeTicks>.
++ static_assert(std::is_trivially_copyable<TimeTicks>(), "");
++
++ // Copy ctor.
++ constexpr TimeTicks a = TimeTicks::FromInternalValue(12345);
++ constexpr TimeTicks b{a};
++ static_assert(a.ToInternalValue() == b.ToInternalValue(), "");
++
++ // Copy assignment.
++ static_assert(a.ToInternalValue() ==
++ TestTimeTicksConstexprCopyAssignment().ToInternalValue(),
++ "");
++}
++
++constexpr ThreadTicks TestThreadTicksConstexprCopyAssignment() {
++ ThreadTicks a = ThreadTicks::FromInternalValue(12345);
++ ThreadTicks b;
++ b = a;
++ return b;
++}
++
++TEST(ThreadTicks, ConstexprAndTriviallyCopiable) {
++ // "Trivially copyable" is necessary for use in std::atomic<ThreadTicks>.
++ static_assert(std::is_trivially_copyable<ThreadTicks>(), "");
++
++ // Copy ctor.
++ constexpr ThreadTicks a = ThreadTicks::FromInternalValue(12345);
++ constexpr ThreadTicks b{a};
++ static_assert(a.ToInternalValue() == b.ToInternalValue(), "");
++
++ // Copy assignment.
++ static_assert(a.ToInternalValue() ==
++ TestThreadTicksConstexprCopyAssignment().ToInternalValue(),
++ "");
++}
++
++constexpr TimeDelta TestTimeDeltaConstexprCopyAssignment() {
++ TimeDelta a = TimeDelta::FromSeconds(1);
++ TimeDelta b;
++ b = a;
++ return b;
++}
++
++TEST(TimeDelta, ConstexprAndTriviallyCopiable) {
++ // "Trivially copyable" is necessary for use in std::atomic<TimeDelta>.
++ static_assert(std::is_trivially_copyable<TimeDelta>(), "");
++
++ // Copy ctor.
++ constexpr TimeDelta a = TimeDelta::FromSeconds(1);
++ constexpr TimeDelta b{a};
++ static_assert(a == b, "");
++
++ // Copy assignment.
++ static_assert(a == TestTimeDeltaConstexprCopyAssignment(), "");
++}
++
+ TEST(TimeDeltaLogging, DCheckEqCompiles) {
+ DCHECK_EQ(TimeDelta(), TimeDelta());
+ }
diff --git a/libchrome_tools/patches/Fix-Wdefaulted-function-deleted-warning-in-MessageLo.patch b/libchrome_tools/patches/Fix-Wdefaulted-function-deleted-warning-in-MessageLo.patch
new file mode 100644
index 000000000..33855143c
--- /dev/null
+++ b/libchrome_tools/patches/Fix-Wdefaulted-function-deleted-warning-in-MessageLo.patch
@@ -0,0 +1,38 @@
+From 91fe99136cd57a8eab9c076e4e1699767bcac3fa Mon Sep 17 00:00:00 2001
+From: Hans Wennborg <hans@chromium.org>
+Date: Tue, 2 Oct 2018 16:25:34 +0000
+Subject: [PATCH] Fix -Wdefaulted-function-deleted warning in
+ MessageLoopCurrent
+
+The new Clang warning points out that the class can't be copy
+assigned because the current_ member is const. Copy or move
+constructing it is fine though, and that's all that's needed.
+
+Bug: 890307
+Change-Id: I3f4d5e69485b84166ba4dd2356cc7973a5e58da6
+Reviewed-on: https://chromium-review.googlesource.com/1255613
+Reviewed-by: Daniel Cheng <dcheng@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#595867}
+---
+ base/message_loop/message_loop_current.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/base/message_loop/message_loop_current.h b/base/message_loop/message_loop_current.h
+index d623cbc7f7b2..403d0dcc2ddb 100644
+--- a/base/message_loop/message_loop_current.h
++++ b/base/message_loop/message_loop_current.h
+@@ -38,9 +38,9 @@ class MessageLoop;
+ class BASE_EXPORT MessageLoopCurrent {
+ public:
+ // MessageLoopCurrent is effectively just a disguised pointer and is fine to
+- // copy around.
++ // copy/move around.
+ MessageLoopCurrent(const MessageLoopCurrent& other) = default;
+- MessageLoopCurrent& operator=(const MessageLoopCurrent& other) = default;
++ MessageLoopCurrent(MessageLoopCurrent&& other) = default;
+
+ // Returns a proxy object to interact with the MessageLoop running the
+ // current thread. It must only be used on the thread it was obtained.
+--
+2.22.0.rc2.383.gf4fbbf30c2-goog
+
diff --git a/libchrome_tools/patches/Mojo-Check-if-dispatcher-is-null-in-Core-UnwrapPlatf.patch b/libchrome_tools/patches/Mojo-Check-if-dispatcher-is-null-in-Core-UnwrapPlatf.patch
new file mode 100644
index 000000000..28ff13bb6
--- /dev/null
+++ b/libchrome_tools/patches/Mojo-Check-if-dispatcher-is-null-in-Core-UnwrapPlatf.patch
@@ -0,0 +1,38 @@
+From 317fd980dd9504d3fe321b53469fee79e3276fed Mon Sep 17 00:00:00 2001
+From: Ryo Hashimoto <hashimoto@chromium.org>
+Date: Thu, 4 Oct 2018 05:04:22 +0000
+Subject: [PATCH] Mojo: Check if dispatcher is null in
+ Core::UnwrapPlatformHandle()
+
+The same check is done in other functions in this .cc file.
+Do the same thing for UnwrapPlatformHandle().
+
+BUG=891990
+TEST=mojo_unittests
+
+Change-Id: I05fe4bfd5edd8ec3fc67aeb9f11879c74fd71dd4
+Reviewed-on: https://chromium-review.googlesource.com/c/1260782
+Reviewed-by: Ken Rockot <rockot@chromium.org>
+Commit-Queue: Ryo Hashimoto <hashimoto@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#596510}
+---
+ mojo/core/core.cc | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/mojo/core/core.cc b/mojo/core/core.cc
+index 8422ec247a40..32ecea3eae55 100644
+--- a/mojo/core/core.cc
++++ b/mojo/core/core.cc
+@@ -1017,7 +1017,8 @@ MojoResult Core::UnwrapPlatformHandle(
+ {
+ base::AutoLock lock(handles_->GetLock());
+ dispatcher = handles_->GetDispatcher(mojo_handle);
+- if (dispatcher->GetType() != Dispatcher::Type::PLATFORM_HANDLE)
++ if (!dispatcher ||
++ dispatcher->GetType() != Dispatcher::Type::PLATFORM_HANDLE)
+ return MOJO_RESULT_INVALID_ARGUMENT;
+
+ MojoResult result =
+--
+2.25.0.225.g125e21ebc7-goog
+
diff --git a/libchrome_tools/patches/Refactor-AlarmTimer-to-report-error-to-the-caller.patch b/libchrome_tools/patches/Refactor-AlarmTimer-to-report-error-to-the-caller.patch
new file mode 100644
index 000000000..196779481
--- /dev/null
+++ b/libchrome_tools/patches/Refactor-AlarmTimer-to-report-error-to-the-caller.patch
@@ -0,0 +1,180 @@
+From 07763c630b9e6ee4538a86d291bfce8357dec934 Mon Sep 17 00:00:00 2001
+From: Hidehiko Abe <hidehiko@chromium.org>
+Date: Thu, 13 Jun 2019 22:12:42 +0900
+Subject: [PATCH] Refactor AlarmTimer to report error to the caller.
+
+This is to address the comment
+https://chromium-review.googlesource.com/c/aosp/platform/external/libchrome/+/1387893/2/components/timers/alarm_timer_chromeos.h#45
+
+Instead of just upstreaming it, which exposes a method unused in Chromium,
+this CL introduces Create() factory method and drops the code to
+fallback in case of timerfd_create failure.
+
+Now, a caller should check whether Create() returns null or not.
+In case of null, to keep the previous behavior, the caller can
+create an instance of the parent class.
+
+Along with the change, in order to run unittest for the class
+without capability CAP_WAKE_ALARM, this CL also introduces CreateForTesting().
+We used to test just fall-back code paths.
+
+In addition, this CL fixes the FD leak on destruction.
+
+This patch modified the original upstream patch, by
+ - keeping the old constructor for backward-compatibility.
+ - keeping CanWakeFromSuspend, and calls of CanWakeFromSuspend from Stop
+ and Reset, for backward-compatibility, so that unittest won't fail
+ due to -1 alarm_fd_ from default constructor when there's no
+ capability to alarm.
+
+BUG=None
+TEST=Build and run components_unittests --gtest_filter=AlarmTimerTest*. Run try.
+
+Change-Id: Ieb9660335120565ccff7f192d7a8192ca1e59ebc
+Reviewed-on: https://chromium-review.googlesource.com/c/1411356
+Reviewed-by: Ryo Hashimoto <hashimoto@chromium.org>
+Reviewed-by: Dmitry Titov <dimich@chromium.org>
+Reviewed-by: Dan Erat <derat@chromium.org>
+Commit-Queue: Hidehiko Abe <hidehiko@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#626151}
+---
+ components/timers/alarm_timer_chromeos.cc | 51 ++++++++++++++---------
+ components/timers/alarm_timer_chromeos.h | 27 +++++++-----
+ 2 files changed, 49 insertions(+), 29 deletions(-)
+
+diff --git a/components/timers/alarm_timer_chromeos.cc b/components/timers/alarm_timer_chromeos.cc
+index 0b43134..371eb67 100644
+--- a/components/timers/alarm_timer_chromeos.cc
++++ b/components/timers/alarm_timer_chromeos.cc
+@@ -15,13 +15,43 @@
+ #include "base/debug/task_annotator.h"
+ #include "base/files/file_util.h"
+ #include "base/logging.h"
++#include "base/memory/ptr_util.h"
+ #include "base/pending_task.h"
+ #include "base/trace_event/trace_event.h"
+
+ namespace timers {
+
++// Keep for backward compatibility to uprev r576279.
+ SimpleAlarmTimer::SimpleAlarmTimer()
+ : alarm_fd_(timerfd_create(CLOCK_REALTIME_ALARM, 0)), weak_factory_(this) {}
++// static
++std::unique_ptr<SimpleAlarmTimer> SimpleAlarmTimer::Create() {
++ return CreateInternal(CLOCK_REALTIME_ALARM);
++}
++
++// static
++std::unique_ptr<SimpleAlarmTimer> SimpleAlarmTimer::CreateForTesting() {
++ // For unittest, use CLOCK_REALTIME in order to run the tests without
++ // CAP_WAKE_ALARM.
++ return CreateInternal(CLOCK_REALTIME);
++}
++
++// static
++std::unique_ptr<SimpleAlarmTimer> SimpleAlarmTimer::CreateInternal(
++ int clockid) {
++ base::ScopedFD alarm_fd(timerfd_create(clockid, TFD_CLOEXEC));
++ if (!alarm_fd.is_valid()) {
++ PLOG(ERROR) << "Failed to create timer fd";
++ return nullptr;
++ }
++
++ // Note: std::make_unique<> cannot be used because the constructor is
++ // private.
++ return base::WrapUnique(new SimpleAlarmTimer(std::move(alarm_fd)));
++}
++
++SimpleAlarmTimer::SimpleAlarmTimer(base::ScopedFD alarm_fd)
++ : alarm_fd_(std::move(alarm_fd)), weak_factory_(this) {}
+
+ SimpleAlarmTimer::~SimpleAlarmTimer() {
+ DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
+@@ -80,7 +97,7 @@ void SimpleAlarmTimer::Reset() {
+ alarm_time.it_value.tv_nsec =
+ (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) *
+ base::Time::kNanosecondsPerMicrosecond;
+- if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0)
++ if (timerfd_settime(alarm_fd_.get(), 0, &alarm_time, NULL) < 0)
+ PLOG(ERROR) << "Error while setting alarm time. Timer will not fire";
+
+ // The timer is running.
+@@ -97,7 +114,7 @@ void SimpleAlarmTimer::Reset() {
+ base::debug::TaskAnnotator().WillQueueTask("SimpleAlarmTimer::Reset",
+ pending_task_.get());
+ alarm_fd_watcher_ = base::FileDescriptorWatcher::WatchReadable(
+- alarm_fd_,
++ alarm_fd_.get(),
+ base::BindRepeating(&SimpleAlarmTimer::OnAlarmFdReadableWithoutBlocking,
+ weak_factory_.GetWeakPtr()));
+ }
+@@ -109,7 +126,7 @@ void SimpleAlarmTimer::OnAlarmFdReadableWithoutBlocking() {
+
+ // Read from |alarm_fd_| to ack the event.
+ char val[sizeof(uint64_t)];
+- if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t)))
++ if (!base::ReadFromFD(alarm_fd_.get(), val, sizeof(uint64_t)))
+ PLOG(DFATAL) << "Unable to read from timer file descriptor.";
+
+ OnTimerFired();
+diff --git a/components/timers/alarm_timer_chromeos.h b/components/timers/alarm_timer_chromeos.h
+index 1ff689e..e1301e9 100644
+--- a/components/timers/alarm_timer_chromeos.h
++++ b/components/timers/alarm_timer_chromeos.h
+@@ -8,6 +8,7 @@
+ #include <memory>
+
+ #include "base/files/file_descriptor_watcher_posix.h"
++#include "base/files/scoped_file.h"
+ #include "base/macros.h"
+ #include "base/memory/scoped_refptr.h"
+ #include "base/memory/weak_ptr.h"
+@@ -24,8 +25,7 @@ namespace timers {
+ // suspended state. For example, this is useful for running tasks that are
+ // needed for maintaining network connectivity, like sending heartbeat messages.
+ // Currently, this feature is only available on Chrome OS systems running linux
+-// version 3.11 or higher. On all other platforms, the SimpleAlarmTimer behaves
+-// exactly the same way as a regular Timer.
++// version 3.11 or higher.
+ //
+ // A SimpleAlarmTimer instance can only be used from the sequence on which it
+ // was instantiated. Start() and Stop() must be called from a thread that
+@@ -36,7 +36,16 @@ namespace timers {
+ // times but not at a regular interval.
+ class SimpleAlarmTimer : public base::RetainingOneShotTimer {
+ public:
+ SimpleAlarmTimer();
++ // Creates the SimpleAlarmTimer instance, or returns null on failure, e.g.,
++ // on a platform without timerfd_* system calls support, or missing
++ // capability (CAP_WAKE_ALARM).
++ static std::unique_ptr<SimpleAlarmTimer> Create();
++
++ // Similar to Create(), but for unittests without capability.
++ // Specifically, uses CLOCK_REALTIME instead of CLOCK_REALTIME_ALARM.
++ static std::unique_ptr<SimpleAlarmTimer> CreateForTesting();
++
+ ~SimpleAlarmTimer() override;
+
+ // Timer overrides.
+@@ -44,6 +52,11 @@ class SimpleAlarmTimer : public base::RetainingOneShotTimer {
+ void Reset() override;
+
+ private:
++ // Shared implementation of Create and CreateForTesting.
++ static std::unique_ptr<SimpleAlarmTimer> CreateInternal(int clockid);
++
++ explicit SimpleAlarmTimer(base::ScopedFD alarm_fd);
++
+ // Called when |alarm_fd_| is readable without blocking. Reads data from
+ // |alarm_fd_| and calls OnTimerFired().
+ void OnAlarmFdReadableWithoutBlocking();
+@@ -61,5 +74,5 @@ class SimpleAlarmTimer : public base::RetainingOneShotTimer {
+ // Timer file descriptor.
+- const int alarm_fd_;
++ const base::ScopedFD alarm_fd_;
+
+ // Watches |alarm_fd_|.
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> alarm_fd_watcher_;
+--
+2.22.0.rc2.383.gf4fbbf30c2-goog
+
diff --git a/libchrome_tools/patches/WaitForServiceToBeAvailable.patch b/libchrome_tools/patches/WaitForServiceToBeAvailable.patch
new file mode 100644
index 000000000..f8f2b63cc
--- /dev/null
+++ b/libchrome_tools/patches/WaitForServiceToBeAvailable.patch
@@ -0,0 +1,45 @@
+From eadafb5815145a401cbfa6da559de01cb35d3a2b Mon Sep 17 00:00:00 2001
+From: Qijiang Fan <fqj@chromium.org>
+Date: Tue, 17 Dec 2019 17:21:54 +0900
+Subject: [PATCH 3/5] mock object proxy WaitForServiceToBeAvailable
+
+Change-Id: I01d2e49547f0e9083df60de69ef254761de2c00e
+---
+ dbus/mock_object_proxy.cc | 5 +++++
+ dbus/mock_object_proxy.h | 6 +++++++
+ 2 files changed, 11 insertions(+)
+
+diff --git a/dbus/mock_object_proxy.cc b/dbus/mock_object_proxy.cc
+index 4929486..a1f2edd 100644
+--- a/dbus/mock_object_proxy.cc
++++ b/dbus/mock_object_proxy.cc
+@@ -45,4 +45,9 @@ void MockObjectProxy::ConnectToSignal(
+ &on_connected_callback);
+ }
+
++void MockObjectProxy::WaitForServiceToBeAvailable(
++ WaitForServiceToBeAvailableCallback callback) {
++ DoWaitForServiceToBeAvailable(&callback);
++}
++
+ } // namespace dbus
+diff --git a/dbus/mock_object_proxy.h b/dbus/mock_object_proxy.h
+index 7bc2376..abc793a 100644
+--- a/dbus/mock_object_proxy.h
++++ b/dbus/mock_object_proxy.h
+@@ -89,6 +90,12 @@ class MockObjectProxy : public ObjectProxy {
+ OnConnectedCallback* on_connected_callback));
+ MOCK_METHOD1(SetNameOwnerChangedCallback,
+ void(NameOwnerChangedCallback callback));
++ // This method is not mockable because it takes a move-only argument. To work
++ // around this. WaitForServiceToBeAvailable implements here calls
++ // DoWaitForServiceToBeAvailable which is mockable.
++ void WaitForServiceToBeAvailable(WaitForServiceToBeAvailableCallback callback) override;
++ MOCK_METHOD1(DoWaitForServiceToBeAvailable,
++ void(WaitForServiceToBeAvailableCallback* callback));
+ MOCK_METHOD0(Detach, void());
+
+ protected:
+--
+2.24.1.735.g03f4e72817-goog
+
diff --git a/libchrome_tools/patches/components-timers-fix-fd-leak-in-AlarmTimer.patch b/libchrome_tools/patches/components-timers-fix-fd-leak-in-AlarmTimer.patch
new file mode 100644
index 000000000..e98c6918d
--- /dev/null
+++ b/libchrome_tools/patches/components-timers-fix-fd-leak-in-AlarmTimer.patch
@@ -0,0 +1,102 @@
+From e18f110107399803dd070088c601f9a5540a2a3f Mon Sep 17 00:00:00 2001
+From: Hidehiko Abe <hidehiko@chromium.org>
+Date: Thu, 3 Oct 2019 02:04:53 +0900
+Subject: [PATCH] components/timers: fix fd leak in AlarmTimer
+
+This is fixed upstream but will take a while to roll back
+into Chrome OS.
+
+BUG=chromium:984593
+TEST=enable/disable wifi repeatedly and see that there is no
+ growth of open timerfds
+
+Change-Id: If2af8f8ddf6b9dc31cda36fe5f5454ca0c5819de
+---
+ components/timers/alarm_timer_chromeos.cc | 8 ++++----
+ components/timers/alarm_timer_chromeos.h | 15 ++++++++-------
+ 2 files changed, 12 insertions(+), 11 deletions(-)
+
+diff --git a/components/timers/alarm_timer_chromeos.cc b/components/timers/alarm_timer_chromeos.cc
+index 0b43134..f14d889 100644
+--- a/components/timers/alarm_timer_chromeos.cc
++++ b/components/timers/alarm_timer_chromeos.cc
+@@ -80,7 +80,7 @@ void SimpleAlarmTimer::Reset() {
+ alarm_time.it_value.tv_nsec =
+ (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) *
+ base::Time::kNanosecondsPerMicrosecond;
+- if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0)
++ if (timerfd_settime(alarm_fd_.get(), 0, &alarm_time, NULL) < 0)
+ PLOG(ERROR) << "Error while setting alarm time. Timer will not fire";
+
+ // The timer is running.
+@@ -97,7 +97,7 @@ void SimpleAlarmTimer::Reset() {
+ base::debug::TaskAnnotator().WillQueueTask("SimpleAlarmTimer::Reset",
+ pending_task_.get());
+ alarm_fd_watcher_ = base::FileDescriptorWatcher::WatchReadable(
+- alarm_fd_,
++ alarm_fd_.get(),
+ base::BindRepeating(&SimpleAlarmTimer::OnAlarmFdReadableWithoutBlocking,
+ weak_factory_.GetWeakPtr()));
+ }
+@@ -109,7 +109,7 @@ void SimpleAlarmTimer::OnAlarmFdReadableWithoutBlocking() {
+
+ // Read from |alarm_fd_| to ack the event.
+ char val[sizeof(uint64_t)];
+- if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t)))
++ if (!base::ReadFromFD(alarm_fd_.get(), val, sizeof(uint64_t)))
+ PLOG(DFATAL) << "Unable to read from timer file descriptor.";
+
+ OnTimerFired();
+@@ -137,7 +137,7 @@ void SimpleAlarmTimer::OnTimerFired() {
+ }
+
+ bool SimpleAlarmTimer::CanWakeFromSuspend() const {
+- return alarm_fd_ != -1;
++ return alarm_fd_.is_valid();
+ }
+
+ } // namespace timers
+diff --git a/components/timers/alarm_timer_chromeos.h b/components/timers/alarm_timer_chromeos.h
+index 1ff689e..100ba81 100644
+--- a/components/timers/alarm_timer_chromeos.h
++++ b/components/timers/alarm_timer_chromeos.h
+@@ -8,6 +8,7 @@
+ #include <memory>
+
+ #include "base/files/file_descriptor_watcher_posix.h"
++#include "base/files/scoped_file.h"
+ #include "base/macros.h"
+ #include "base/memory/scoped_refptr.h"
+ #include "base/memory/weak_ptr.h"
+@@ -43,6 +44,12 @@ class SimpleAlarmTimer : public base::RetainingOneShotTimer {
+ void Stop() override;
+ void Reset() override;
+
++ // Tracks whether the timer has the ability to wake the system up from
++ // suspend. This is a runtime check because we won't know if the system
++ // supports being woken up from suspend until the constructor actually tries
++ // to set it up.
++ bool CanWakeFromSuspend() const;
++
+ private:
+ // Called when |alarm_fd_| is readable without blocking. Reads data from
+ // |alarm_fd_| and calls OnTimerFired().
+@@ -51,14 +58,8 @@ class SimpleAlarmTimer : public base::RetainingOneShotTimer {
+ // Called when the timer fires. Runs the callback.
+ void OnTimerFired();
+
+- // Tracks whether the timer has the ability to wake the system up from
+- // suspend. This is a runtime check because we won't know if the system
+- // supports being woken up from suspend until the constructor actually tries
+- // to set it up.
+- bool CanWakeFromSuspend() const;
+-
+ // Timer file descriptor.
+- const int alarm_fd_;
++ base::ScopedFD alarm_fd_;
+
+ // Watches |alarm_fd_|.
+ std::unique_ptr<base::FileDescriptorWatcher::Controller> alarm_fd_watcher_;
+--
+2.23.0.581.g78d2f28ef7-goog
+
diff --git a/libchrome_tools/patches/dbus-Add-TryRegisterFallback.patch b/libchrome_tools/patches/dbus-Add-TryRegisterFallback.patch
new file mode 100644
index 000000000..b0ef0b815
--- /dev/null
+++ b/libchrome_tools/patches/dbus-Add-TryRegisterFallback.patch
@@ -0,0 +1,137 @@
+From a4d8dee3905d784f40d8f480eaacae2655e68b47 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Wed, 11 Jul 2018 20:55:58 -0700
+Subject: [PATCH] dbus: Add TryRegisterFallback
+
+The TryRegisterFallback works just like TryRegisterObjectPath,
+with addition that the registered callbacks also apply to the specified
+object path and its sub paths. This is useful to implement a "catch-all"
+handler.
+
+Currently this is needed by Bluetooth dispatcher which needs to catch
+all method calls to all objects and forward them to another D-Bus
+service.
+
+Bug:862849
+---
+ dbus/bus.cc | 27 +++++++++++++++++++++------
+ dbus/bus.h | 32 ++++++++++++++++++++++++++++++++
+ dbus/mock_bus.h | 5 +++++
+ 3 files changed, 58 insertions(+), 6 deletions(-)
+
+diff --git a/dbus/bus.cc b/dbus/bus.cc
+index e62058e0dc34..29043609e760 100644
+--- a/dbus/bus.cc
++++ b/dbus/bus.cc
+@@ -722,6 +722,25 @@ bool Bus::TryRegisterObjectPath(const ObjectPath& object_path,
+ const DBusObjectPathVTable* vtable,
+ void* user_data,
+ DBusError* error) {
++ return TryRegisterObjectPathInternal(
++ object_path, vtable, user_data, error,
++ dbus_connection_try_register_object_path);
++}
++
++bool Bus::TryRegisterFallback(const ObjectPath& object_path,
++ const DBusObjectPathVTable* vtable,
++ void* user_data,
++ DBusError* error) {
++ return TryRegisterObjectPathInternal(object_path, vtable, user_data, error,
++ dbus_connection_try_register_fallback);
++}
++
++bool Bus::TryRegisterObjectPathInternal(
++ const ObjectPath& object_path,
++ const DBusObjectPathVTable* vtable,
++ void* user_data,
++ DBusError* error,
++ TryRegisterObjectPathFunction* register_function) {
+ DCHECK(connection_);
+ AssertOnDBusThread();
+
+@@ -731,12 +750,8 @@ bool Bus::TryRegisterObjectPath(const ObjectPath& object_path,
+ return false;
+ }
+
+- const bool success = dbus_connection_try_register_object_path(
+- connection_,
+- object_path.value().c_str(),
+- vtable,
+- user_data,
+- error);
++ const bool success = register_function(
++ connection_, object_path.value().c_str(), vtable, user_data, error);
+ if (success)
+ registered_object_paths_.insert(object_path);
+ return success;
+diff --git a/dbus/bus.h b/dbus/bus.h
+index c2c2685afdc4..704a4c3a0b54 100644
+--- a/dbus/bus.h
++++ b/dbus/bus.h
+@@ -520,6 +520,24 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
+ void* user_data,
+ DBusError* error);
+
++ // Tries to register the object path and its sub paths.
++ // Returns true on success.
++ // Returns false if the object path is already registered.
++ //
++ // |message_function| in |vtable| will be called every time when a new
++ // message sent to the object path (or hierarchically below) arrives.
++ //
++ // The same object path must not be added more than once.
++ //
++ // See also documentation of |dbus_connection_try_register_fallback| at
++ // http://dbus.freedesktop.org/doc/api/html/group__DBusConnection.html
++ //
++ // BLOCKING CALL.
++ virtual bool TryRegisterFallback(const ObjectPath& object_path,
++ const DBusObjectPathVTable* vtable,
++ void* user_data,
++ DBusError* error);
++
+ // Unregister the object path.
+ //
+ // BLOCKING CALL.
+@@ -590,8 +608,22 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
+ virtual ~Bus();
+
+ private:
++ using TryRegisterObjectPathFunction =
++ dbus_bool_t(DBusConnection* connection,
++ const char* object_path,
++ const DBusObjectPathVTable* vtable,
++ void* user_data,
++ DBusError* error);
++
+ friend class base::RefCountedThreadSafe<Bus>;
+
++ bool TryRegisterObjectPathInternal(
++ const ObjectPath& object_path,
++ const DBusObjectPathVTable* vtable,
++ void* user_data,
++ DBusError* error,
++ TryRegisterObjectPathFunction* register_function);
++
+ // Helper function used for RemoveObjectProxy().
+ void RemoveObjectProxyInternal(scoped_refptr<dbus::ObjectProxy> object_proxy,
+ const base::Closure& callback);
+diff --git a/dbus/mock_bus.h b/dbus/mock_bus.h
+index 216bc64bd068..6b3495db6014 100644
+--- a/dbus/mock_bus.h
++++ b/dbus/mock_bus.h
+@@ -62,6 +62,11 @@ class MockBus : public Bus {
+ const DBusObjectPathVTable* vtable,
+ void* user_data,
+ DBusError* error));
++ MOCK_METHOD4(TryRegisterFallback,
++ bool(const ObjectPath& object_path,
++ const DBusObjectPathVTable* vtable,
++ void* user_data,
++ DBusError* error));
+ MOCK_METHOD1(UnregisterObjectPath, void(const ObjectPath& object_path));
+ MOCK_METHOD0(GetDBusTaskRunner, base::TaskRunner*());
+ MOCK_METHOD0(GetOriginTaskRunner, base::TaskRunner*());
+--
+2.18.0.203.gfac676dfb9-goog
+
diff --git a/libchrome_tools/patches/dbus-Make-Bus-is_connected-mockable.patch b/libchrome_tools/patches/dbus-Make-Bus-is_connected-mockable.patch
new file mode 100644
index 000000000..3dd2c8869
--- /dev/null
+++ b/libchrome_tools/patches/dbus-Make-Bus-is_connected-mockable.patch
@@ -0,0 +1,93 @@
+From 59bc1c00682f45d54a05aadc2a2e0559f85e4499 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Thu, 16 Aug 2018 05:09:20 +0000
+Subject: [PATCH] dbus: Make Bus::is_connected() mockable
+
+It's currently not possible to have a unit test that triggers
+Bus::is_connected() because it always returns false. This is currently
+needed by the Bluetooth dispatcher (btdispatch) in Chrome OS.
+
+Bug: 866704
+Change-Id: I04f7e8a22792886d421479c1c7c621eeb27d3a2a
+Reviewed-on: https://chromium-review.googlesource.com/1175216
+Reviewed-by: Ryo Hashimoto <hashimoto@chromium.org>
+Commit-Queue: Sonny Sasaka <sonnysasaka@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#583543}
+---
+ dbus/bus.cc | 4 ++++
+ dbus/bus.h | 2 +-
+ dbus/bus_unittest.cc | 4 ++--
+ dbus/exported_object.cc | 2 +-
+ dbus/mock_bus.h | 1 +
+ dbus/object_proxy.cc | 2 +-
+ 6 files changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/dbus/bus.cc b/dbus/bus.cc
+index 2f3db885f561..9d37656ac21c 100644
+--- a/dbus/bus.cc
++++ b/dbus/bus.cc
+@@ -997,6 +997,10 @@ std::string Bus::GetConnectionName() {
+ return dbus_bus_get_unique_name(connection_);
+ }
+
++bool Bus::IsConnected() {
++ return connection_ != nullptr;
++}
++
+ dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch) {
+ AssertOnDBusThread();
+
+diff --git a/dbus/bus.h b/dbus/bus.h
+index 704a4c3a0b54..b082110e589b 100644
+--- a/dbus/bus.h
++++ b/dbus/bus.h
+@@ -601,7 +601,7 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
+ std::string GetConnectionName();
+
+ // Returns true if the bus is connected to D-Bus.
+- bool is_connected() { return connection_ != nullptr; }
++ virtual bool IsConnected();
+
+ protected:
+ // This is protected, so we can define sub classes.
+diff --git a/dbus/exported_object.cc b/dbus/exported_object.cc
+index d6c91b6d2046..5fa1b916f251 100644
+--- a/dbus/exported_object.cc
++++ b/dbus/exported_object.cc
+@@ -280,7 +280,7 @@ void ExportedObject::OnMethodCompleted(std::unique_ptr<MethodCall> method_call,
+
+ // Check if the bus is still connected. If the method takes long to
+ // complete, the bus may be shut down meanwhile.
+- if (!bus_->is_connected())
++ if (!bus_->IsConnected())
+ return;
+
+ if (!response) {
+diff --git a/dbus/mock_bus.h b/dbus/mock_bus.h
+index 6b3495db6014..22807622786a 100644
+--- a/dbus/mock_bus.h
++++ b/dbus/mock_bus.h
+@@ -73,6 +73,7 @@ class MockBus : public Bus {
+ MOCK_METHOD0(HasDBusThread, bool());
+ MOCK_METHOD0(AssertOnOriginThread, void());
+ MOCK_METHOD0(AssertOnDBusThread, void());
++ MOCK_METHOD0(IsConnected, bool());
+
+ protected:
+ ~MockBus() override;
+diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc
+index aa5102aec792..3046dbb5f38b 100644
+--- a/dbus/object_proxy.cc
++++ b/dbus/object_proxy.cc
+@@ -288,7 +288,7 @@ void ObjectProxy::WaitForServiceToBeAvailable(
+ void ObjectProxy::Detach() {
+ bus_->AssertOnDBusThread();
+
+- if (bus_->is_connected())
++ if (bus_->IsConnected())
+ bus_->RemoveFilterFunction(&ObjectProxy::HandleMessageThunk, this);
+
+ for (const auto& match_rule : match_rules_) {
+--
+2.21.0.392.gf8f6787159e-goog
+
diff --git a/libchrome_tools/patches/dbus-Remove-LOG-ERROR-in-ObjectProxy.patch b/libchrome_tools/patches/dbus-Remove-LOG-ERROR-in-ObjectProxy.patch
new file mode 100644
index 000000000..62bdd940e
--- /dev/null
+++ b/libchrome_tools/patches/dbus-Remove-LOG-ERROR-in-ObjectProxy.patch
@@ -0,0 +1,58 @@
+From ad887b5aaf4f834dbbd487adfe89d9a5b3d673f2 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Thu, 9 Aug 2018 22:39:57 +0000
+Subject: [PATCH] dbus: Remove LOG(ERROR) in ObjectProxy
+
+It is a valid use case for a daemon to have multiple ObjectProxies of
+different services with the exact same object path and interface name.
+Currently, this may cause log pollution of "rejecting a message from a
+wrong sender" because one ObjectProxy receives signals intended for
+another ObjectProxy. Since it's actually a valid case and not a bug, it
+shouldn't be logged as error but it may still be logged with VLOG.
+
+Currently this is discovered in Bluetooth daemon (btdispatch) because it
+listens to both BlueZ's and Newblue's objects which have identical
+object paths and interfaces.
+
+Bug: 866704
+Change-Id: I25b6437ec6081e244a47c635c0adedf281530967
+Reviewed-on: https://chromium-review.googlesource.com/1164474
+Reviewed-by: Ryo Hashimoto <hashimoto@chromium.org>
+Commit-Queue: Sonny Sasaka <sonnysasaka@chromium.org>
+Cr-Commit-Position: refs/heads/master@{#581937}
+---
+ dbus/object_proxy.cc | 11 +++++------
+ 1 file changed, 5 insertions(+), 6 deletions(-)
+
+diff --git a/dbus/object_proxy.cc b/dbus/object_proxy.cc
+index 35835fbdc32c..aa5102aec792 100644
+--- a/dbus/object_proxy.cc
++++ b/dbus/object_proxy.cc
+@@ -519,6 +519,11 @@ DBusHandlerResult ObjectProxy::HandleMessage(
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
++ std::string sender = signal->GetSender();
++ // Ignore message from sender we are not interested in.
++ if (service_name_owner_ != sender)
++ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
++
+ const std::string interface = signal->GetInterface();
+ const std::string member = signal->GetMember();
+
+@@ -534,12 +539,6 @@ DBusHandlerResult ObjectProxy::HandleMessage(
+ }
+ VLOG(1) << "Signal received: " << signal->ToString();
+
+- std::string sender = signal->GetSender();
+- if (service_name_owner_ != sender) {
+- LOG(ERROR) << "Rejecting a message from a wrong sender.";
+- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+- }
+-
+ const base::TimeTicks start_time = base::TimeTicks::Now();
+ if (bus_->HasDBusThread()) {
+ // Post a task to run the method in the origin thread.
+--
+2.21.0.392.gf8f6787159e-goog
+
diff --git a/libchrome_tools/patches/dbus-Support-UnexportMethod-from-an-exported-object.patch b/libchrome_tools/patches/dbus-Support-UnexportMethod-from-an-exported-object.patch
new file mode 100644
index 000000000..1a797bf2a
--- /dev/null
+++ b/libchrome_tools/patches/dbus-Support-UnexportMethod-from-an-exported-object.patch
@@ -0,0 +1,194 @@
+From fb915ed71679feafd4ed53deb2c5ba84862a9e57 Mon Sep 17 00:00:00 2001
+From: Sonny Sasaka <sonnysasaka@chromium.org>
+Date: Mon, 10 Dec 2018 14:03:49 -0800
+Subject: [PATCH] dbus: Support UnexportMethod from an exported object.
+
+Currently there is no way to override a method handler that is already
+registered to an ExportedObject. A support to do so is required to
+correctly implement Chrome OS Bluetooth dispatcher which needs to
+add/remove an interface to an exported object dynamically. Therefore
+this CL adds methods to allow method handlers to be unexported so
+another handler can be exported afterwards.
+
+Bug: 883039
+---
+ dbus/exported_object.cc | 50 +++++++++++++++++++++++++++++++++++++
+ dbus/exported_object.h | 34 +++++++++++++++++++++++++
+ dbus/mock_exported_object.h | 7 ++++++
+ 3 files changed, 91 insertions(+)
+
+diff --git a/dbus/exported_object.cc b/dbus/exported_object.cc
+index 5fa1b916f251..727a5707b869 100644
+--- a/dbus/exported_object.cc
++++ b/dbus/exported_object.cc
+@@ -68,6 +68,22 @@ bool ExportedObject::ExportMethodAndBlock(
+ return true;
+ }
+
++bool ExportedObject::UnexportMethodAndBlock(const std::string& interface_name,
++ const std::string& method_name) {
++ bus_->AssertOnDBusThread();
++
++ const std::string absolute_method_name =
++ GetAbsoluteMemberName(interface_name, method_name);
++ if (method_table_.find(absolute_method_name) == method_table_.end()) {
++ LOG(ERROR) << absolute_method_name << " is not exported";
++ return false;
++ }
++
++ method_table_.erase(absolute_method_name);
++
++ return true;
++}
++
+ void ExportedObject::ExportMethod(const std::string& interface_name,
+ const std::string& method_name,
+ MethodCallCallback method_call_callback,
+@@ -83,6 +99,18 @@ void ExportedObject::ExportMethod(const std::string& interface_name,
+ bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
+ }
+
++void ExportedObject::UnexportMethod(
++ const std::string& interface_name,
++ const std::string& method_name,
++ OnUnexportedCallback on_unexported_calback) {
++ bus_->AssertOnOriginThread();
++
++ base::Closure task =
++ base::Bind(&ExportedObject::UnexportMethodInternal, this, interface_name,
++ method_name, on_unexported_calback);
++ bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
++}
++
+ void ExportedObject::SendSignal(Signal* signal) {
+ // For signals, the object path should be set to the path to the sender
+ // object, which is this exported object here.
+@@ -141,6 +169,19 @@ void ExportedObject::ExportMethodInternal(
+ success));
+ }
+
++void ExportedObject::UnexportMethodInternal(
++ const std::string& interface_name,
++ const std::string& method_name,
++ OnUnexportedCallback on_unexported_calback) {
++ bus_->AssertOnDBusThread();
++
++ const bool success = UnexportMethodAndBlock(interface_name, method_name);
++ bus_->GetOriginTaskRunner()->PostTask(
++ FROM_HERE,
++ base::Bind(&ExportedObject::OnUnexported, this, on_unexported_calback,
++ interface_name, method_name, success));
++}
++
+ void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
+ const std::string& interface_name,
+ const std::string& method_name,
+@@ -150,6 +191,15 @@ void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
+ on_exported_callback.Run(interface_name, method_name, success);
+ }
+
++void ExportedObject::OnUnexported(OnExportedCallback on_unexported_callback,
++ const std::string& interface_name,
++ const std::string& method_name,
++ bool success) {
++ bus_->AssertOnOriginThread();
++
++ on_unexported_callback.Run(interface_name, method_name, success);
++}
++
+ void ExportedObject::SendSignalInternal(base::TimeTicks start_time,
+ DBusMessage* signal_message) {
+ uint32_t serial = 0;
+diff --git a/dbus/exported_object.h b/dbus/exported_object.h
+index 69a63a5e075e..d314083430ef 100644
+--- a/dbus/exported_object.h
++++ b/dbus/exported_object.h
+@@ -60,6 +60,13 @@ class CHROME_DBUS_EXPORT ExportedObject
+ bool success)>
+ OnExportedCallback;
+
++ // Called when method unexporting is done.
++ // |success| indicates whether unexporting was successful or not.
++ typedef base::Callback<void(const std::string& interface_name,
++ const std::string& method_name,
++ bool success)>
++ OnUnexportedCallback;
++
+ // Exports the method specified by |interface_name| and |method_name|,
+ // and blocks until exporting is done. Returns true on success.
+ //
+@@ -81,6 +88,11 @@ class CHROME_DBUS_EXPORT ExportedObject
+ const std::string& method_name,
+ MethodCallCallback method_call_callback);
+
++ // Unexports the method specified by |interface_name| and |method_name|,
++ // and blocks until unexporting is done. Returns true on success.
++ virtual bool UnexportMethodAndBlock(const std::string& interface_name,
++ const std::string& method_name);
++
+ // Requests to export the method specified by |interface_name| and
+ // |method_name|. See Also ExportMethodAndBlock().
+ //
+@@ -93,6 +105,17 @@ class CHROME_DBUS_EXPORT ExportedObject
+ MethodCallCallback method_call_callback,
+ OnExportedCallback on_exported_callback);
+
++ // Requests to unexport the method specified by |interface_name| and
++ // |method_name|. See also UnexportMethodAndBlock().
++ //
++ // |on_unexported_callback| is called when the method is unexported or
++ // failed to be unexported, in the origin thread.
++ //
++ // Must be called in the origin thread.
++ virtual void UnexportMethod(const std::string& interface_name,
++ const std::string& method_name,
++ OnUnexportedCallback on_unexported_callback);
++
+ // Requests to send the signal from this object. The signal will be sent
+ // synchronously if this method is called from the message loop in the D-Bus
+ // thread and asynchronously otherwise.
+@@ -117,12 +140,23 @@ class CHROME_DBUS_EXPORT ExportedObject
+ MethodCallCallback method_call_callback,
+ OnExportedCallback exported_callback);
+
++ // Helper function for UnexportMethod().
++ void UnexportMethodInternal(const std::string& interface_name,
++ const std::string& method_name,
++ OnUnexportedCallback unexported_callback);
++
+ // Called when the object is exported.
+ void OnExported(OnExportedCallback on_exported_callback,
+ const std::string& interface_name,
+ const std::string& method_name,
+ bool success);
+
++ // Called when a method is unexported.
++ void OnUnexported(OnExportedCallback on_unexported_callback,
++ const std::string& interface_name,
++ const std::string& method_name,
++ bool success);
++
+ // Helper function for SendSignal().
+ void SendSignalInternal(base::TimeTicks start_time,
+ DBusMessage* signal_message);
+diff --git a/dbus/mock_exported_object.h b/dbus/mock_exported_object.h
+index 99c363f9b532..9d5b3a894179 100644
+--- a/dbus/mock_exported_object.h
++++ b/dbus/mock_exported_object.h
+@@ -28,6 +28,13 @@ class MockExportedObject : public ExportedObject {
+ const std::string& method_name,
+ MethodCallCallback method_call_callback,
+ OnExportedCallback on_exported_callback));
++ MOCK_METHOD2(UnexportMethodAndBlock,
++ bool(const std::string& interface_name,
++ const std::string& method_name));
++ MOCK_METHOD3(UnexportMethod,
++ void(const std::string& interface_name,
++ const std::string& method_name,
++ OnUnexportedCallback on_unexported_callback));
+ MOCK_METHOD1(SendSignal, void(Signal* signal));
+ MOCK_METHOD0(Unregister, void());
+
+--
+2.20.0.rc2.403.gdbc3b29805-goog
+
diff --git a/libchrome_tools/patches/enable-location-source.patch b/libchrome_tools/patches/enable-location-source.patch
new file mode 100644
index 000000000..adcafb4c8
--- /dev/null
+++ b/libchrome_tools/patches/enable-location-source.patch
@@ -0,0 +1,26 @@
+From 8f8b73113f4e785543129c806d0e57bcf13d2314 Mon Sep 17 00:00:00 2001
+From: Qijiang Fan <fqj@chromium.org>
+Date: Wed, 18 Dec 2019 17:47:58 +0900
+Subject: [PATCH 4/4] enable location source
+
+Change-Id: I29fd847bc0fa0ace7a9637417a796b64b32485e3
+---
+ base/debug/debugging_buildflags.h | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/base/debug/debugging_buildflags.h b/base/debug/debugging_buildflags.h
+index 33e3dd0..a974f83 100644
+--- a/base/debug/debugging_buildflags.h
++++ b/base/debug/debugging_buildflags.h
+@@ -6,7 +6,7 @@
+ #define BUILDFLAG_INTERNAL_ENABLE_PROFILING() (0)
+ #define BUILDFLAG_INTERNAL_ENABLE_MEMORY_TASK_PROFILER() (0)
+ #define BUILDFLAG_INTERNAL_CAN_UNWIND_WITH_FRAME_POINTERS() (0)
+-#define BUILDFLAG_INTERNAL_ENABLE_LOCATION_SOURCE() (0)
++#define BUILDFLAG_INTERNAL_ENABLE_LOCATION_SOURCE() (1)
+ #define BUILDFLAG_INTERNAL_CFI_ENFORCEMENT_TRAP() (0)
+ #define BUILDFLAG_INTERNAL_ENABLE_MUTEX_PRIORITY_INHERITANCE() (0)
+ #endif // BASE_DEBUG_DEBUGGING_FLAGS_H_
+--
+2.24.1.735.g03f4e72817-goog
+
diff --git a/libchrome_tools/patches/fix-fd-watcher-leak.patch b/libchrome_tools/patches/fix-fd-watcher-leak.patch
new file mode 100644
index 000000000..510d077a6
--- /dev/null
+++ b/libchrome_tools/patches/fix-fd-watcher-leak.patch
@@ -0,0 +1,188 @@
+From 9ae1384af2cdd16539e9caaed69b095737e2c272 Mon Sep 17 00:00:00 2001
+From: Qijiang Fan <fqj@chromium.org>
+Date: Tue, 17 Dec 2019 17:32:35 +0900
+Subject: [PATCH] backport upstream patch to fix watcher leak.
+
+https://chromium-review.googlesource.com/c/chromium/src/+/695914
+
+Change-Id: I91928fc00e9845ff75c49c272ff774ff9810f4eb
+---
+ base/files/file_descriptor_watcher_posix.cc | 104 +++++++++++++++-----
+ base/threading/thread_restrictions.h | 4 +
+ 2 files changed, 82 insertions(+), 26 deletions(-)
+
+diff --git a/base/files/file_descriptor_watcher_posix.cc b/base/files/file_descriptor_watcher_posix.cc
+index b26bf6c..98d2cec 100644
+--- a/base/files/file_descriptor_watcher_posix.cc
++++ b/base/files/file_descriptor_watcher_posix.cc
+@@ -5,6 +5,7 @@
+ #include "base/files/file_descriptor_watcher_posix.h"
+
+ #include "base/bind.h"
++#include "base/callback_helpers.h"
+ #include "base/lazy_instance.h"
+ #include "base/logging.h"
+ #include "base/memory/ptr_util.h"
+@@ -12,6 +13,7 @@
+ #include "base/message_loop/message_pump_for_io.h"
+ #include "base/sequenced_task_runner.h"
+ #include "base/single_thread_task_runner.h"
++#include "base/synchronization/waitable_event.h"
+ #include "base/threading/sequenced_task_runner_handle.h"
+ #include "base/threading/thread_checker.h"
+ #include "base/threading/thread_local.h"
+@@ -27,21 +29,7 @@ LazyInstance<ThreadLocalPointer<MessageLoopForIO>>::Leaky
+
+ } // namespace
+
+-FileDescriptorWatcher::Controller::~Controller() {
+- DCHECK(sequence_checker_.CalledOnValidSequence());
+-
+- // Delete |watcher_| on the MessageLoopForIO.
+- //
+- // If the MessageLoopForIO is deleted before Watcher::StartWatching() runs,
+- // |watcher_| is leaked. If the MessageLoopForIO is deleted after
+- // Watcher::StartWatching() runs but before the DeleteSoon task runs,
+- // |watcher_| is deleted from Watcher::WillDestroyCurrentMessageLoop().
+- message_loop_for_io_task_runner_->DeleteSoon(FROM_HERE, watcher_.release());
+-
+- // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be
+- // invoked after this returns.
+-}
+-
++// Move watcher above to prevent delete incomplete type at delete watcher later.
+ class FileDescriptorWatcher::Controller::Watcher
+ : public MessagePumpForIO::FdWatcher,
+ public MessageLoopCurrent::DestructionObserver {
+@@ -90,6 +78,58 @@ class FileDescriptorWatcher::Controller::Watcher
+ DISALLOW_COPY_AND_ASSIGN(Watcher);
+ };
+
++FileDescriptorWatcher::Controller::~Controller() {
++ DCHECK(sequence_checker_.CalledOnValidSequence());
++
++ if (message_loop_for_io_task_runner_->BelongsToCurrentThread()) {
++ // If the MessageLoopForIO and the Controller live on the same thread.
++ watcher_.reset();
++ } else {
++ // Synchronously wait until |watcher_| is deleted on the MessagePumpForIO
++ // thread. This ensures that the file descriptor is never accessed after
++ // this destructor returns.
++ //
++ // Use a ScopedClosureRunner to ensure that |done| is signaled even if the
++ // thread doesn't run any more tasks (if PostTask returns true, it means
++ // that the task was queued, but it doesn't mean that a RunLoop will run the
++ // task before the queue is deleted).
++ //
++ // We considered associating "generations" to file descriptors to avoid the
++ // synchronous wait. For example, if the IO thread gets a "cancel" for fd=6,
++ // generation=1 after getting a "start watching" for fd=6, generation=2, it
++ // can ignore the "Cancel". However, "generations" didn't solve this race:
++ //
++ // T1 (client) Start watching fd = 6 with WatchReadable()
++ // Stop watching fd = 6
++ // Close fd = 6
++ // Open a new file, fd = 6 gets reused.
++ // T2 (io) Watcher::StartWatching()
++ // Incorrectly starts watching fd = 6 which now refers to a
++ // different file than when WatchReadable() was called.
++ WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
++ WaitableEvent::InitialState::NOT_SIGNALED);
++ message_loop_for_io_task_runner_->PostTask(
++ FROM_HERE, BindOnce(
++ [](Watcher *watcher, ScopedClosureRunner closure) {
++ // Since |watcher| is a raw pointer, it isn't deleted
++ // if this callback is deleted before it gets to run.
++ delete watcher;
++ // |closure| runs at the end of this scope.
++ },
++ Unretained(watcher_.release()),
++ // TODO(fqj): change to BindOnce after some uprev.
++ ScopedClosureRunner(Bind(&WaitableEvent::Signal,
++ Unretained(&done)))));
++ // TODO(fqj): change to ScopedAllowBaseSyncPrimitivesOutsideBlockingScope
++ // after uprev to r586297
++ base::ThreadRestrictions::ScopedAllowWait allow_wait __attribute__((unused));
++ done.Wait();
++ }
++
++ // Since WeakPtrs are invalidated by the destructor, RunCallback() won't be
++ // invoked after this returns.
++}
++
+ FileDescriptorWatcher::Controller::Watcher::Watcher(
+ WeakPtr<Controller> controller,
+ MessagePumpForIO::Mode mode,
+@@ -150,11 +190,19 @@ void FileDescriptorWatcher::Controller::Watcher::
+ WillDestroyCurrentMessageLoop() {
+ DCHECK(thread_checker_.CalledOnValidThread());
+
+- // A Watcher is owned by a Controller. When the Controller is deleted, it
+- // transfers ownership of the Watcher to a delete task posted to the
+- // MessageLoopForIO. If the MessageLoopForIO is deleted before the delete task
+- // runs, the following line takes care of deleting the Watcher.
+- delete this;
++ if (callback_task_runner_->RunsTasksInCurrentSequence()) {
++ // |controller_| can be accessed directly when Watcher runs on the same
++ // thread.
++ controller_->watcher_.reset();
++ } else {
++ // If the Watcher and the Controller live on different threads, delete
++ // |this| synchronously. Pending tasks bound to an unretained Watcher* will
++ // not run since this loop is dead. The associated Controller still
++ // technically owns this via unique_ptr but it never uses it directly and
++ // will ultimately send it to this thread for deletion (and that also won't
++ // run since the loop being dead).
++ delete this;
++ }
+ }
+
+ FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode,
+@@ -172,12 +220,16 @@ FileDescriptorWatcher::Controller::Controller(MessagePumpForIO::Mode mode,
+
+ void FileDescriptorWatcher::Controller::StartWatching() {
+ DCHECK(sequence_checker_.CalledOnValidSequence());
+- // It is safe to use Unretained() below because |watcher_| can only be deleted
+- // by a delete task posted to |message_loop_for_io_task_runner_| by this
+- // Controller's destructor. Since this delete task hasn't been posted yet, it
+- // can't run before the task posted below.
+- message_loop_for_io_task_runner_->PostTask(
+- FROM_HERE, BindOnce(&Watcher::StartWatching, Unretained(watcher_.get())));
++ if (message_loop_for_io_task_runner_->BelongsToCurrentThread()) {
++ watcher_->StartWatching();
++ } else {
++ // It is safe to use Unretained() below because |watcher_| can only be deleted
++ // by a delete task posted to |message_loop_for_io_task_runner_| by this
++ // Controller's destructor. Since this delete task hasn't been posted yet, it
++ // can't run before the task posted below.
++ message_loop_for_io_task_runner_->PostTask(
++ FROM_HERE, Bind(&Watcher::StartWatching, Unretained(watcher_.get())));
++ }
+ }
+
+ void FileDescriptorWatcher::Controller::RunCallback() {
+diff --git a/base/threading/thread_restrictions.h b/base/threading/thread_restrictions.h
+index 705ba4d..7532f85 100644
+--- a/base/threading/thread_restrictions.h
++++ b/base/threading/thread_restrictions.h
+@@ -147,6 +147,7 @@ namespace internal {
+ class TaskTracker;
+ }
+
++class FileDescriptorWatcher;
+ class GetAppOutputScopedAllowBaseSyncPrimitives;
+ class SimpleThread;
+ class StackSamplingProfiler;
+@@ -479,6 +480,9 @@ class BASE_EXPORT ThreadRestrictions {
+ friend class ui::CommandBufferLocal;
+ friend class ui::GpuState;
+
++ // Chrome OS libchrome
++ friend class base::FileDescriptorWatcher;
++
+ // END ALLOWED USAGE.
+ // BEGIN USAGE THAT NEEDS TO BE FIXED.
+ friend class ::chromeos::BlockingMethodCaller; // http://crbug.com/125360
+--
+2.24.1.735.g03f4e72817-goog
+
diff --git a/libchrome_tools/patches/libchrome-Add-EmptyResponseCallback-for-backward-com.patch b/libchrome_tools/patches/libchrome-Add-EmptyResponseCallback-for-backward-com.patch
new file mode 100644
index 000000000..80c6dfaea
--- /dev/null
+++ b/libchrome_tools/patches/libchrome-Add-EmptyResponseCallback-for-backward-com.patch
@@ -0,0 +1,42 @@
+From f34f528c1fc4512910b2acc586e678ddb53eaf9e Mon Sep 17 00:00:00 2001
+From: Hidehiko Abe <hidehiko@chromium.org>
+Date: Wed, 2 Oct 2019 09:53:00 +0900
+Subject: [PATCH] libchrome: Add EmptyResponseCallback for backward
+ compatiblity.
+
+BUG=chromium:909719
+TEST=Build locally.
+
+Change-Id: I4d6c75f267fd6c170b966647c30c91bb02b3ee14
+---
+ dbus/object_proxy.h | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/dbus/object_proxy.h b/dbus/object_proxy.h
+index 22e44f1..7d62eb9 100644
+--- a/dbus/object_proxy.h
++++ b/dbus/object_proxy.h
+@@ -13,6 +13,7 @@
+ #include <string>
+ #include <vector>
+
++#include "base/bind.h"
+ #include "base/callback.h"
+ #include "base/macros.h"
+ #include "base/memory/ref_counted.h"
+@@ -105,6 +106,12 @@ class CHROME_DBUS_EXPORT ObjectProxy
+ using OnConnectedCallback =
+ base::OnceCallback<void(const std::string&, const std::string&, bool)>;
+
++ // TOOD(crbug.com/909719): This is just for backward compatibility.
++ // Remove this callback after clients are migrated.
++ static ResponseCallback EmptyResponseCallback() {
++ return base::BindOnce([](Response*){});
++ }
++
+ // Calls the method of the remote object and blocks until the response
+ // is returned. Returns NULL on error with the error details specified
+ // in the |error| object.
+--
+2.23.0.581.g78d2f28ef7-goog
+
diff --git a/libchrome_tools/patches/libchrome-Introduce-stub-ConvertableToTraceFormat.patch b/libchrome_tools/patches/libchrome-Introduce-stub-ConvertableToTraceFormat.patch
new file mode 100644
index 000000000..bd68077cc
--- /dev/null
+++ b/libchrome_tools/patches/libchrome-Introduce-stub-ConvertableToTraceFormat.patch
@@ -0,0 +1,55 @@
+From f2d560ab2808c87cd60a2962037bf4dabd9781ef Mon Sep 17 00:00:00 2001
+From: Hidehiko Abe <hidehiko@chromium.org>
+Date: Fri, 14 Jun 2019 14:22:33 +0900
+Subject: [PATCH] libchrome: Introduce stub ConvertableToTraceFormat.
+
+BUG=chromium:909719
+TEST=Built locally.
+
+Change-Id: I5c849edc2c5e8370bff6a8b1b83a92e5ef5836c8
+---
+ base/trace_event/trace_event.h | 13 ++++++++++++-
+ 1 file changed, 12 insertions(+), 1 deletion(-)
+
+diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
+index 1ce76d9..7385582 100644
+--- a/base/trace_event/trace_event.h
++++ b/base/trace_event/trace_event.h
+@@ -10,6 +10,9 @@
+ #include "base/trace_event/common/trace_event_common.h"
+ #include "base/trace_event/heap_profiler.h"
+
++// Indirectly included.
++#include "base/strings/string_util.h"
++
+ // To avoid -Wunused-* errors, eat expression by macro.
+ namespace libchrome_internal {
+ template <typename... Args> void Ignore(Args&&... args) {}
+@@ -18,8 +21,9 @@ template <typename... Args> void Ignore(Args&&... args) {}
+ (false ? libchrome_internal::Ignore(__VA_ARGS__) : (void) 0)
+
+ // Body is effectively empty.
++#define INTERNAL_TRACE_EVENT_ADD(...) INTERNAL_IGNORE(__VA_ARGS__)
+ #define INTERNAL_TRACE_EVENT_ADD_SCOPED(...) INTERNAL_IGNORE(__VA_ARGS__)
+-#define INTERNAL_TRACE_TASK_EXECUTION(...)
++#define INTERNAL_TRACE_TASK_EXECUTION(...) INTERNAL_IGNORE(__VA_ARGS__)
+ #define INTERNAL_TRACE_EVENT_ADD_SCOPED_WITH_FLOW(...) \
+ INTERNAL_IGNORE(__VA_ARGS__)
+ #define TRACE_ID_MANGLE(val) (val)
+@@ -38,6 +42,13 @@ class TraceLog {
+ void SetCurrentThreadBlocksMessageLoop() {}
+ };
+
++class BASE_EXPORT ConvertableToTraceFormat {
++ public:
++ ConvertableToTraceFormat() = default;
++ virtual ~ConvertableToTraceFormat() = default;
++ virtual void AppendAsTraceFormat(std::string* out) const {};
++};
++
+ } // namespace trace_event
+ } // namespace base
+ #else
+--
+2.22.0.410.gd8fdbe21b5-goog
+
diff --git a/libchrome_tools/patches/libchrome-Remove-glib-dependency.patch b/libchrome_tools/patches/libchrome-Remove-glib-dependency.patch
new file mode 100644
index 000000000..418dba196
--- /dev/null
+++ b/libchrome_tools/patches/libchrome-Remove-glib-dependency.patch
@@ -0,0 +1,31 @@
+[200~From 78a4103946854e4e526b0cf407f0b09610b40988 Mon Sep 17 00:00:00 2001
+From: hscham <hscham@chromium.org>
+Date: Mon, 1 Jun 2020 16:50:16 +0900
+Subject: [PATCH] libchrome: Remove glib dependency.
+
+BUG=chromium:361635
+TEST=Ran Pre-CQ.
+
+Change-Id: I8a583851d51c5eaa24bb1506d45d6566f760595c
+---
+ build/build_config.h | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/build/build_config.h b/build/build_config.h
+index 0a0024088..b0e2aa26e 100644
+--- a/build/build_config.h
++++ b/build/build_config.h
+@@ -39,10 +39,6 @@
+ #elif !defined(__ANDROID_HOST__) // Chrome OS
+
+ #define OS_CHROMEOS 1
+-// TODO: Remove these once the GLib MessageLoopForUI isn't being used:
+-// https://crbug.com/361635
+-#define USE_GLIB 1
+-#define USE_OZONE 1
+
+ #endif // defined(__ANDROID__)
+
+--
+2.27.0.rc2.251.g90737beb825-goog
+
diff --git a/libchrome_tools/patches/libchrome-Unpatch-sys.path-update.patch b/libchrome_tools/patches/libchrome-Unpatch-sys.path-update.patch
new file mode 100644
index 000000000..89d124479
--- /dev/null
+++ b/libchrome_tools/patches/libchrome-Unpatch-sys.path-update.patch
@@ -0,0 +1,41 @@
+From 702acfbe733e5b047759a3bfee71c8b63e5814fe Mon Sep 17 00:00:00 2001
+From: Hidehiko Abe <hidehiko@chromium.org>
+Date: Thu, 13 Jun 2019 23:02:42 +0900
+Subject: [PATCH] libchrome: Unpatch sys.path update.
+
+Unlike soong build, original sys.path change works.
+
+BUG=chromium:909719
+TEST=Built locally.
+
+Change-Id: I6c8ac8d4a1d156ddd77ec75485d42a810a9e61fe
+---
+ build/android/gyp/util/build_utils.py | 12 ++----------
+ 1 file changed, 2 insertions(+), 10 deletions(-)
+
+diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py
+index 426de03..f1764b9 100644
+--- a/build/android/gyp/util/build_utils.py
++++ b/build/android/gyp/util/build_utils.py
+@@ -25,16 +25,8 @@ import zipfile
+ # Some clients do not add //build/android/gyp to PYTHONPATH.
+ import md5_check # pylint: disable=relative-import
+
+-# pylib conflicts with mojo/public/tools/bindings/pylib. Prioritize
+-# build/android/pylib.
+-# PYTHONPATH wouldn't help in this case, because soong put source files under
+-# temp directory for each build, so the abspath is unknown until the
+-# execution.
+-#sys.path.append(os.path.join(os.path.dirname(__file__),
+-# os.pardir, os.pardir, os.pardir))
+-sys.path.insert(0, os.path.join(os.path.dirname(__file__),
+- os.pardir, os.pardir))
+-
++sys.path.append(os.path.join(os.path.dirname(__file__),
++ os.pardir, os.pardir, os.pardir))
+ import gn_helpers
+
+ # Definition copied from pylib/constants/__init__.py to avoid adding
+--
+2.22.0.rc2.383.gf4fbbf30c2-goog
+
diff --git a/libchrome_tools/patches/libchrome-Update-crypto.patch b/libchrome_tools/patches/libchrome-Update-crypto.patch
new file mode 100644
index 000000000..45991605c
--- /dev/null
+++ b/libchrome_tools/patches/libchrome-Update-crypto.patch
@@ -0,0 +1,182 @@
+From 23ecc2149133fa0cf369f53b5d7d28e78815bca3 Mon Sep 17 00:00:00 2001
+From: Hidehiko Abe <hidehiko@chromium.org>
+Date: Thu, 13 Jun 2019 22:27:41 +0900
+Subject: [PATCH] libchrome: Update crypto.
+
+libchrome uses OpenSSH, instead of BoringSSH, although its support
+was dropped in Chrome already.
+To lengthen its lifetime, this patch adds minor fix.
+- Use base::data() instead of base::string_as_array().
+ The method was removed. cf) crrev.com/c/1056014.
+- Use base::PostTaskAndReply instead of base::WorkerPool.
+ The class was removed. cf) crrev.com/c/650368
+- tracked_object::Location is renamed to base::Location.
+ cf) crbug.com/763556
+- base::Location::Write was removed. Use ToString().
+ cf) crrev.com/c/707310
+- base::MakeUnique was removed. Use std::make_unique.
+ cf) crrev.com/c/944048
+
+BUG=chromium:909719
+TEST=Built locally.
+
+Change-Id: I2ba45db7592ea9addc2df230b977ffb950f0b342
+---
+ crypto/nss_util.cc | 37 ++++++++++++++-----------------------
+ crypto/openssl_util.cc | 6 ++----
+ crypto/openssl_util.h | 7 +++----
+ crypto/sha2.cc | 2 +-
+ 4 files changed, 20 insertions(+), 32 deletions(-)
+
+diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
+index a7752d3..f9c6373 100644
+--- a/crypto/nss_util.cc
++++ b/crypto/nss_util.cc
+@@ -38,14 +38,13 @@
+ #include "base/files/file_util.h"
+ #include "base/lazy_instance.h"
+ #include "base/logging.h"
+-#include "base/memory/ptr_util.h"
+ #include "base/message_loop/message_loop.h"
+ #include "base/native_library.h"
+ #include "base/stl_util.h"
+ #include "base/strings/stringprintf.h"
++#include "base/task_scheduler/post_task.h"
+ #include "base/threading/thread_checker.h"
+ #include "base/threading/thread_restrictions.h"
+-#include "base/threading/worker_pool.h"
+ #include "build/build_config.h"
+
+ #if !defined(OS_CHROMEOS)
+@@ -380,22 +379,16 @@ class NSSInitSingleton {
+ std::unique_ptr<TPMModuleAndSlot> tpm_args(
+ new TPMModuleAndSlot(chaps_module_));
+ TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
+- if (base::WorkerPool::PostTaskAndReply(
+- FROM_HERE,
+- base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
+- system_slot_id,
+- tpm_args_ptr),
+- base::Bind(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
+- base::Unretained(this), // NSSInitSingleton is leaky
+- callback,
+- base::Passed(&tpm_args)),
+- true /* task_is_slow */
+- )) {
+- initializing_tpm_token_ = true;
+- } else {
+- base::MessageLoop::current()->task_runner()->PostTask(
+- FROM_HERE, base::Bind(callback, false));
+- }
++ base::PostTaskAndReply(
++ FROM_HERE,
++ base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
++ system_slot_id,
++ tpm_args_ptr),
++ base::Bind(&NSSInitSingleton::OnInitializedTPMTokenAndSystemSlot,
++ base::Unretained(this), // NSSInitSingleton is leaky
++ callback,
++ base::Passed(&tpm_args)));
++ initializing_tpm_token_ = true;
+ }
+
+ static void InitializeTPMTokenOnWorkerThread(CK_SLOT_ID token_slot_id,
+@@ -508,7 +501,7 @@ class NSSInitSingleton {
+ "%s %s", kUserNSSDatabaseName, username_hash.c_str());
+ ScopedPK11Slot public_slot(OpenPersistentNSSDBForPath(db_name, path));
+ chromeos_user_map_[username_hash] =
+- base::MakeUnique<ChromeOSUserData>(std::move(public_slot));
++ std::make_unique<ChromeOSUserData>(std::move(public_slot));
+ return true;
+ }
+
+@@ -543,7 +536,7 @@ class NSSInitSingleton {
+ std::unique_ptr<TPMModuleAndSlot> tpm_args(
+ new TPMModuleAndSlot(chaps_module_));
+ TPMModuleAndSlot* tpm_args_ptr = tpm_args.get();
+- base::WorkerPool::PostTaskAndReply(
++ base::PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&NSSInitSingleton::InitializeTPMTokenOnWorkerThread,
+ slot_id,
+@@ -551,9 +544,7 @@ class NSSInitSingleton {
+ base::Bind(&NSSInitSingleton::OnInitializedTPMForChromeOSUser,
+ base::Unretained(this), // NSSInitSingleton is leaky
+ username_hash,
+- base::Passed(&tpm_args)),
+- true /* task_is_slow */
+- );
++ base::Passed(&tpm_args)));
+ }
+
+ void OnInitializedTPMForChromeOSUser(
+diff --git a/crypto/openssl_util.cc b/crypto/openssl_util.cc
+index c1b7a90..b671eab 100644
+--- a/crypto/openssl_util.cc
++++ b/crypto/openssl_util.cc
+@@ -46,15 +46,13 @@ void EnsureOpenSSLInit() {
+ #endif
+ }
+
+-void ClearOpenSSLERRStack(const tracked_objects::Location& location) {
++void ClearOpenSSLERRStack(const base::Location& location) {
+ if (DCHECK_IS_ON() && VLOG_IS_ON(1)) {
+ uint32_t error_num = ERR_peek_error();
+ if (error_num == 0)
+ return;
+
+- std::string message;
+- location.Write(true, true, &message);
+- DVLOG(1) << "OpenSSL ERR_get_error stack from " << message;
++ DVLOG(1) << "OpenSSL ERR_get_error stack from " << location.ToString();
+ ERR_print_errors_cb(&OpenSSLErrorCallback, NULL);
+ } else {
+ ERR_clear_error();
+diff --git a/crypto/openssl_util.h b/crypto/openssl_util.h
+index d608cde..c3d6cc9 100644
+--- a/crypto/openssl_util.h
++++ b/crypto/openssl_util.h
+@@ -63,8 +63,7 @@ CRYPTO_EXPORT void EnsureOpenSSLInit();
+ // Drains the OpenSSL ERR_get_error stack. On a debug build the error codes
+ // are send to VLOG(1), on a release build they are disregarded. In most
+ // cases you should pass FROM_HERE as the |location|.
+-CRYPTO_EXPORT void ClearOpenSSLERRStack(
+- const tracked_objects::Location& location);
++CRYPTO_EXPORT void ClearOpenSSLERRStack(const base::Location& location);
+
+ // Place an instance of this class on the call stack to automatically clear
+ // the OpenSSL error stack on function exit.
+@@ -73,7 +72,7 @@ class OpenSSLErrStackTracer {
+ // Pass FROM_HERE as |location|, to help track the source of OpenSSL error
+ // messages. Note any diagnostic emitted will be tagged with the location of
+ // the constructor call as it's not possible to trace a destructor's callsite.
+- explicit OpenSSLErrStackTracer(const tracked_objects::Location& location)
++ explicit OpenSSLErrStackTracer(const base::Location& location)
+ : location_(location) {
+ EnsureOpenSSLInit();
+ }
+@@ -82,7 +81,7 @@ class OpenSSLErrStackTracer {
+ }
+
+ private:
+- const tracked_objects::Location location_;
++ const base::Location location_;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(OpenSSLErrStackTracer);
+ };
+diff --git a/crypto/sha2.cc b/crypto/sha2.cc
+index 1b302b3..71566a9 100644
+--- a/crypto/sha2.cc
++++ b/crypto/sha2.cc
+@@ -21,7 +21,7 @@ void SHA256HashString(const base::StringPiece& str, void* output, size_t len) {
+
+ std::string SHA256HashString(const base::StringPiece& str) {
+ std::string output(kSHA256Length, 0);
+- SHA256HashString(str, base::string_as_array(&output), output.size());
++ SHA256HashString(str, base::data(output), output.size());
+ return output;
+ }
+
+--
+2.22.0.rc2.383.gf4fbbf30c2-goog
+
diff --git a/libchrome_tools/patches/libchrome-fix-integer-overflow-if-microseconds-is-IN.patch b/libchrome_tools/patches/libchrome-fix-integer-overflow-if-microseconds-is-IN.patch
new file mode 100644
index 000000000..a1241b11d
--- /dev/null
+++ b/libchrome_tools/patches/libchrome-fix-integer-overflow-if-microseconds-is-IN.patch
@@ -0,0 +1,27 @@
+From f7ef75a1ddea9d18e1f166b76e90f948cbfd1f77 Mon Sep 17 00:00:00 2001
+From: Qijiang Fan <fqj@chromium.org>
+Date: Tue, 31 Mar 2020 17:43:16 +0900
+Subject: [PATCH] libchrome: fix integer overflow if microseconds is INT64_MIN
+
+Change-Id: Id3641f6b625f716ae6d134002c0224ed32284939
+---
+ base/time/time_exploded_posix.cc | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/base/time/time_exploded_posix.cc b/base/time/time_exploded_posix.cc
+index 627c6b4f8735..2aef3864554e 100644
+--- a/base/time/time_exploded_posix.cc
++++ b/base/time/time_exploded_posix.cc
+@@ -141,8 +141,7 @@ void Time::Explode(bool is_local, Exploded* exploded) const {
+ millisecond = milliseconds % kMillisecondsPerSecond;
+ } else {
+ // Round these *down* (towards -infinity).
+- milliseconds = (microseconds - kMicrosecondsPerMillisecond + 1) /
+- kMicrosecondsPerMillisecond;
++ milliseconds = (microseconds + 1) / kMicrosecondsPerMillisecond - 1;
+ seconds =
+ (milliseconds - kMillisecondsPerSecond + 1) / kMillisecondsPerSecond;
+ // Make this nonnegative (and between 0 and 999 inclusive).
+--
+2.24.1
+
diff --git a/libchrome_tools/patches/patches b/libchrome_tools/patches/patches
new file mode 100644
index 000000000..eef1769ac
--- /dev/null
+++ b/libchrome_tools/patches/patches
@@ -0,0 +1,72 @@
+# This file will be used by emerge in libchrome-XXXX.ebuild to determine the
+# order of applying patches.
+
+# Cherry pick CLs from upstream.
+# Remove these when the libchrome gets enough new.
+# r576565.
+dbus-Add-TryRegisterFallback.patch
+
+# r581937.
+dbus-Remove-LOG-ERROR-in-ObjectProxy.patch
+
+# r582324
+Fix-Wdefaulted-function-deleted-warning-in-MessageLo.patch
+
+# r583543.
+dbus-Make-Bus-is_connected-mockable.patch
+
+# r596510.
+Mojo-Check-if-dispatcher-is-null-in-Core-UnwrapPlatf.patch
+
+# This no_destructor.h is taken from r599267.
+Add-base-NoDestructor-T.patch
+
+# r616020.
+dbus-Support-UnexportMethod-from-an-exported-object.patch
+
+# Add support for SimpleAlarmTimer::Create{,ForTesting} to reflect changes in r626151.
+Refactor-AlarmTimer-to-report-error-to-the-caller.patch
+
+# For backward compatibility.
+# TODO(crbug.com/909719): Remove this patch after clients are updated.
+libchrome-Add-EmptyResponseCallback-for-backward-com.patch
+
+# Undo gn_helper sys.path update.
+libchrome-Unpatch-sys.path-update.patch
+
+# Introduce stub ConvertableToTraceFormat for task_scheduler.
+libchrome-Introduce-stub-ConvertableToTraceFormat.patch
+
+# Fix timing issue with dbus::ObjectManager.
+# # TODO(bingxue): Remove after libchrome uprev past r684392.
+Connect-to-NameOwnerChanged-signal-when-setting-call.patch
+
+# Remove glib dependency.
+# TODO(hidehiko): Fix the config in AOSP libchrome.
+libchrome-Remove-glib-dependency.patch
+
+# Fix FileDescriptorWatcher leak
+# TODO(fqj): Remove after libchrome past r627021.
+fix-fd-watcher-leak.patch
+
+# Misc fix to build older crypto library.
+libchrome-Update-crypto.patch
+
+# Enable location source to add function_name
+enable-location-source.patch
+
+# Add WaitForServiceToBeAvailable back for MockObjectProxy
+WaitForServiceToBeAvailable.patch
+
+# TODO(crbug.com/1044363): Remove after uprev >= r586219.
+Fix-TimeDelta.patch
+
+# TODO(crbug.com/1065504): Remove after uprev to 754979.
+libchrome-fix-integer-overflow-if-microseconds-is-IN.patch
+
+# Forward compatibility for r680000
+r680000-forward-compatibility-patch-part-1.patch
+r680000-forward-compatibility-patch-part-2.patch
+
+# Add base/{check_op,notreached}.h for cbor
+Add-header-files-base-check_op-notreached-h.patch
diff --git a/libchrome_tools/patches/r680000-forward-compatibility-patch-part-1.patch b/libchrome_tools/patches/r680000-forward-compatibility-patch-part-1.patch
new file mode 100644
index 000000000..2f820e683
--- /dev/null
+++ b/libchrome_tools/patches/r680000-forward-compatibility-patch-part-1.patch
@@ -0,0 +1,222 @@
+From 9d210ed05abf5e527f1de0b30fff62a8a3ae548f Mon Sep 17 00:00:00 2001
+From: hscham <hscham@chromium.org>
+Date: Mon, 13 Apr 2020 10:36:11 +0900
+Subject: [PATCH] libchrome: r680000 forward compatibility patch part 1
+
+This CL includes:
+- Add header files base/hash/{hash,md5,sha1}.h and
+ base/system/sys_info.h from base/.
+- Add macro PRFilePath.
+- Add JSONReader::{Read,ReadAndReturnError,ReadToValue}Deprecated, alias
+ of the corresponding method without the Deprecated suffix.
+- Add empty class base::CheckedObserver.
+- Add bool operators == and != for base::RepeatingCallback.
+- ScopedClearLastError (up to r758621)
+
+Change-Id: I6ba15f2938c02729e4fd51e5a4a52cb94e7c2a4e
+---
+ base/callback.h | 8 ++++++++
+ base/files/file_path.h | 1 +
+ base/hash/hash.h | 8 ++++++++
+ base/hash/md5.h | 10 ++++++++++
+ base/hash/sha1.h | 10 ++++++++++
+ base/json/json_reader.h | 19 +++++++++++++++++++
+ base/observer_list_types.h | 24 ++++++++++++++++++++++++
+ base/system/sys_info.h | 10 ++++++++++
+ 8 files changed, 90 insertions(+)
+ create mode 100644 base/hash/hash.h
+ create mode 100644 base/hash/md5.h
+ create mode 100644 base/hash/sha1.h
+ create mode 100644 base/observer_list_types.h
+ create mode 100644 base/system/sys_info.h
+
+diff --git a/base/callback.h b/base/callback.h
+index bcda5af58..22a6f0e3e 100644
+--- a/base/callback.h
++++ b/base/callback.h
+@@ -123,6 +123,14 @@ class RepeatingCallback<R(Args...)> : public internal::CallbackBaseCopyable {
+ return EqualsInternal(other);
+ }
+
++ bool operator==(const RepeatingCallback& other) const {
++ return EqualsInternal(other);
++ }
++
++ bool operator!=(const RepeatingCallback& other) const {
++ return !operator==(other);
++ }
++
+ R Run(Args... args) const & {
+ PolymorphicInvoke f =
+ reinterpret_cast<PolymorphicInvoke>(this->polymorphic_invoke());
+diff --git a/base/files/file_path.h b/base/files/file_path.h
+index 2dc15f9d0..36229979d 100644
+--- a/base/files/file_path.h
++++ b/base/files/file_path.h
+@@ -131,6 +131,7 @@
+ #define PRIsFP "ls"
+ #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
+ #define PRIsFP "s"
++#define PRFilePath "s"
+ #endif // OS_WIN
+
+ namespace base {
+diff --git a/base/hash/hash.h b/base/hash/hash.h
+new file mode 100644
+index 000000000..b35a96fd3
+--- /dev/null
++++ b/base/hash/hash.h
+@@ -0,0 +1,8 @@
++// Copyright (c) 2011 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_HASH_HASH_H_
++#define BASE_HASH_HASH_H_
++#include "base/hash.h"
++#endif // BASE_HASH_HASH_H_
+diff --git a/base/hash/md5.h b/base/hash/md5.h
+new file mode 100644
+index 000000000..821649319
+--- /dev/null
++++ b/base/hash/md5.h
+@@ -0,0 +1,10 @@
++// Copyright (c) 2011 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_HASH_MD5_H_
++#define BASE_HASH_MD5_H_
++
++#include "base/md5.h"
++
++#endif // BASE_HASH_MD5_H_
+diff --git a/base/hash/sha1.h b/base/hash/sha1.h
+new file mode 100644
+index 000000000..7d3e18212
+--- /dev/null
++++ b/base/hash/sha1.h
+@@ -0,0 +1,10 @@
++// Copyright (c) 2011 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_HASH_SHA1_H_
++#define BASE_HASH_SHA1_H_
++
++#include "base/sha1.h"
++
++#endif // BASE_HASH_SHA1_H_
+diff --git a/base/json/json_reader.h b/base/json/json_reader.h
+index 2c6bd3e47..05de907ce 100644
+--- a/base/json/json_reader.h
++++ b/base/json/json_reader.h
+@@ -98,6 +98,12 @@ class BASE_EXPORT JSONReader {
+ static std::unique_ptr<Value> Read(StringPiece json,
+ int options = JSON_PARSE_RFC,
+ int max_depth = kStackMaxDepth);
++ inline static std::unique_ptr<Value> ReadDeprecated(
++ StringPiece json,
++ int options = JSON_PARSE_RFC,
++ int max_depth = kStackMaxDepth){
++ return Read(json, options, max_depth);
++ }
+
+ // Reads and parses |json| like Read(). |error_code_out| and |error_msg_out|
+ // are optional. If specified and nullptr is returned, they will be populated
+@@ -110,6 +116,16 @@ class BASE_EXPORT JSONReader {
+ std::string* error_msg_out,
+ int* error_line_out = nullptr,
+ int* error_column_out = nullptr);
++ inline static std::unique_ptr<Value> ReadAndReturnErrorDeprecated(
++ StringPiece json,
++ int options, // JSONParserOptions
++ int* error_code_out,
++ std::string* error_msg_out,
++ int* error_line_out = nullptr,
++ int* error_column_out = nullptr){
++ return ReadAndReturnError(json, options, error_code_out, error_msg_out,
++ error_line_out, error_column_out);
++ }
+
+ // Converts a JSON parse error code into a human readable message.
+ // Returns an empty string if error_code is JSON_NO_ERROR.
+@@ -117,6 +133,9 @@ class BASE_EXPORT JSONReader {
+
+ // Non-static version of Read() above.
+ std::unique_ptr<Value> ReadToValue(StringPiece json);
++ inline std::unique_ptr<Value> ReadToValueDeprecated(StringPiece json) {
++ return JSONReader::ReadToValue(json);
++ }
+
+ // Returns the error code if the last call to ReadToValue() failed.
+ // Returns JSON_NO_ERROR otherwise.
+diff --git a/base/observer_list_types.h b/base/observer_list_types.h
+new file mode 100644
+index 000000000..8f3889735
+--- /dev/null
++++ b/base/observer_list_types.h
+@@ -0,0 +1,24 @@
++// Copyright 2018 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_OBSERVER_LIST_TYPES_H_
++#define BASE_OBSERVER_LIST_TYPES_H_
++
++#include "base/base_export.h"
++#include "base/macros.h"
++
++namespace base {
++class BASE_EXPORT CheckedObserver {
++ public:
++ CheckedObserver() {};
++
++ protected:
++ virtual ~CheckedObserver() = default;
++
++ DISALLOW_COPY_AND_ASSIGN(CheckedObserver);
++};
++
++} // namespace base
++
++#endif // BASE_OBSERVER_LIST_TYPES_H_
+diff --git a/base/scoped_clear_last_error.h b/base/scoped_clear_last_error.h
+new file mode 100644
+index 0000000..066730d
+--- /dev/null
++++ b/base/scoped_clear_last_error.h
+@@ -0,0 +1,14 @@
++// Copyright (c) 2013 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_SCOPED_CLEAR_LAST_ERROR_H_
++#define BASE_SCOPED_CLEAR_LAST_ERROR_H_
++
++#include "base/scoped_clear_errno.h"
++
++namespace base {
++using ScopedClearLastError = base::ScopedClearErrno;
++}
++
++#endif // BASE_SCOPED_CLEAR_LAST_ERROR_H_
+diff --git a/base/system/sys_info.h b/base/system/sys_info.h
+new file mode 100644
+index 000000000..60676e0e1
+--- /dev/null
++++ b/base/system/sys_info.h
+@@ -0,0 +1,10 @@
++// Copyright (c) 2012 The Chromium Authors. All rights reserved.
++// Use of this source code is governed by a BSD-style license that can be
++// found in the LICENSE file.
++
++#ifndef BASE_SYSTEM_SYS_INFO_H_
++#define BASE_SYSTEM_SYS_INFO_H_
++
++#include "base/sys_info.h"
++
++#endif // BASE_SYSTEM_SYS_INFO_H_
+--
+2.26.1.301.g55bc3eb7cb9-goog
+
diff --git a/libchrome_tools/patches/r680000-forward-compatibility-patch-part-2.patch b/libchrome_tools/patches/r680000-forward-compatibility-patch-part-2.patch
new file mode 100644
index 000000000..0bb346d30
--- /dev/null
+++ b/libchrome_tools/patches/r680000-forward-compatibility-patch-part-2.patch
@@ -0,0 +1,94 @@
+From e8ce13950e6afc97ea69a36f5f234a7409269086 Mon Sep 17 00:00:00 2001
+From: hscham <hscham@chromium.org>
+Date: Fri, 17 Apr 2020 15:20:53 +0900
+Subject: [PATCH] libchrome: r680000 forward compatibility patch part 2
+
+This CL includes:
+- Rename base::LaunchOptions {,clear_}environ{=>ment}.
+
+Change-Id: I07b9b84d153e942368021be7fb89f0dd07ffebb1
+---
+ base/process/launch.h | 6 +++---
+ base/process/launch_posix.cc | 8 ++++----
+ base/process/process_util_unittest.cc | 4 ++--
+ 3 files changed, 9 insertions(+), 9 deletions(-)
+
+diff --git a/base/process/launch.h b/base/process/launch.h
+index 7a2def2..84d176e 100644
+--- a/base/process/launch.h
++++ b/base/process/launch.h
+@@ -160,11 +160,11 @@ struct BASE_EXPORT LaunchOptions {
+ // Set/unset environment variables. These are applied on top of the parent
+ // process environment. Empty (the default) means to inherit the same
+ // environment. See AlterEnvironment().
+- EnvironmentMap environ;
++ EnvironmentMap environment;
+
+ // Clear the environment for the new process before processing changes from
+- // |environ|.
+- bool clear_environ = false;
++ // |environment|.
++ bool clear_environment = false;
+
+ // Remap file descriptors according to the mapping of src_fd->dest_fd to
+ // propagate FDs into the child process.
+diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc
+index ec58488..c61db41 100644
+--- a/base/process/launch_posix.cc
++++ b/base/process/launch_posix.cc
+@@ -324,10 +324,10 @@ Process LaunchProcess(const std::vector<std::string>& argv,
+ std::unique_ptr<char* []> new_environ;
+ char* const empty_environ = nullptr;
+ char* const* old_environ = GetEnvironment();
+- if (options.clear_environ)
++ if (options.clear_environment)
+ old_environ = &empty_environ;
+- if (!options.environ.empty())
+- new_environ = AlterEnvironment(old_environ, options.environ);
++ if (!options.environment.empty())
++ new_environ = AlterEnvironment(old_environ, options.environment);
+
+ sigset_t full_sigset;
+ sigfillset(&full_sigset);
+@@ -466,7 +466,7 @@ Process LaunchProcess(const std::vector<std::string>& argv,
+ fd_shuffle2.push_back(InjectionArc(value.first, value.second, false));
+ }
+
+- if (!options.environ.empty() || options.clear_environ)
++ if (!options.environment.empty() || options.clear_environment)
+ SetEnvironment(new_environ.get());
+
+ // fd_shuffle1 is mutated by this call because it cannot malloc.
+diff --git a/base/process/process_util_unittest.cc b/base/process/process_util_unittest.cc
+index 4e788b7..a541e48 100644
+--- a/base/process/process_util_unittest.cc
++++ b/base/process/process_util_unittest.cc
+@@ -1162,8 +1162,8 @@ std::string TestLaunchProcess(const std::vector<std::string>& args,
+
+ LaunchOptions options;
+ options.wait = true;
+- options.environ = env_changes;
+- options.clear_environ = clear_environ;
++ options.environment = env_changes;
++ options.clear_environment = clear_environ;
+ options.fds_to_remap.emplace_back(fds[1], 1);
+ #if defined(OS_LINUX)
+ options.clone_flags = clone_flags;
+--
+2.26.1.301.g55bc3eb7cb9-goog
+
+diff --git a/base/test/scoped_task_environment.h b/base/test/scoped_task_environment.h
+index f9523b3138ec..a2cc7f73d8f2 100644
+--- a/base/test/scoped_task_environment.h
++++ b/base/test/scoped_task_environment.h
+@@ -81,6 +81,10 @@ class ScopedTaskEnvironment {
+ IO,
+ };
+
++ // To introduce TimeSource::MOCK_TIME behaves same as
++ // MainThreadType::MOCK_TIME.
++ using TimeSource = MainThreadType;
++
+ enum class ExecutionMode {
+ // Tasks are queued and only executed when RunUntilIdle() is explicitly
+ // called.
diff --git a/libchrome_tools/update_libchrome.py b/libchrome_tools/update_libchrome.py
new file mode 100644
index 000000000..b2f8a92d5
--- /dev/null
+++ b/libchrome_tools/update_libchrome.py
@@ -0,0 +1,212 @@
+#!/usr/bin/python3
+
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Updates libchrome.
+
+This script uprevs the libchrome library with newer Chromium code.
+How to use:
+
+Prepare your local Chromium repository with the target revision.
+$ cd external/libchrome
+$ python3 libchrome_tools/update_libchrome.py \
+ --chromium_root=${PATH_TO_YOUR_LOCAL_CHROMIUM_REPO}
+
+This script does following things;
+- Clean existing libchrome code, except some manually created files and tools.
+- Copy necessary files from original Chromium repository.
+- Apply patches to the copied files, if necessary.
+"""
+
+
+import argparse
+import fnmatch
+import glob
+import os
+import re
+import shutil
+import subprocess
+
+
+_TOOLS_DIR = os.path.dirname(os.path.realpath(__file__))
+_LIBCHROME_ROOT = os.path.dirname(_TOOLS_DIR)
+
+
+# Files in this list or in the directory listed here will be just copied.
+# Paths ends with '/' is interpreted as directory.
+_IMPORT_LIST = [
+ 'mojo/',
+ 'third_party/ply/',
+ 'third_party/markupsafe/',
+ 'third_party/jinja2/',
+]
+
+# Files which are in the repository, but should not be imported from Chrome
+# repository.
+_IMPORT_BLACKLIST = [
+ # Libchrome specific files.
+ '.gitignore',
+ 'Android.bp',
+ 'MODULE_LICENSE_BSD',
+ 'NOTICE',
+ 'OWNERS',
+ 'SConstruct',
+ 'libmojo.pc.in',
+ 'testrunner.cc',
+ '*/DEPS',
+
+ # No Chromium OWNERS should be imported.
+ '*/OWNERS',
+
+ # libchrome_tools and soong are out of the update target.
+ 'libchrome_tools/*',
+ 'soong/*',
+
+ # No internal directories.
+ 'mojo/internal/*',
+
+ # Those files should be generated. Please see also buildflag_header.patch.
+ 'base/allocator/buildflags.h',
+ 'base/android/java/src/org/chromium/base/BuildConfig.java',
+ 'base/cfi_buildflags.h',
+ 'base/debug/debugging_buildflags.h',
+ 'base/memory/protected_memory_buildflags.h',
+ 'base/synchronization/synchronization_buildflags.h',
+ 'gen/*',
+ 'ipc/ipc_buildflags.h',
+
+ # Blacklist several third party libraries; system libraries should be used.
+ 'base/third_party/libevent/*',
+ 'base/third_party/symbolize/*',
+
+ 'testing/gmock/*',
+ 'testing/gtest/*',
+ 'third_party/ashmem/*',
+ 'third_party/modp_b64/*',
+ 'third_party/protobuf/*',
+]
+
+def _find_target_files(chromium_root):
+ """Returns target files to be upreved."""
+ # Files in the repository should be updated.
+ output = subprocess.check_output(
+ ['git', 'ls-tree', '-r', '--name-only', '--full-name', 'HEAD'],
+ cwd=_LIBCHROME_ROOT).decode('utf-8')
+
+ # Files in _IMPORT_LIST are copied in the following section, so
+ # exclude them from candidates, here, so that files deleted in chromium
+ # repository will be deleted on update.
+ candidates = [
+ path for path in output.splitlines()
+ if not any(path.startswith(import_path) for import_path in _IMPORT_LIST)]
+
+ # All files listed in _IMPORT_LIST should be imported, too.
+ for import_path in _IMPORT_LIST:
+ import_root = os.path.join(chromium_root, import_path)
+
+ # If it is a file, just add to the candidates.
+ if os.path.isfile(import_root):
+ candidates.append(import_path)
+ continue
+
+ # If it is a directory, traverse all files in the directory recursively
+ # and add all of them to candidates.
+ for dirpath, dirnames, filenames in os.walk(import_root):
+ for filename in filenames:
+ filepath = os.path.join(dirpath, filename)
+ candidates.append(os.path.relpath(filepath, chromium_root))
+
+ # Apply blacklist.
+ exclude_pattern = re.compile('|'.join(
+ '(?:%s)' % fnmatch.translate(pattern) for pattern in _IMPORT_BLACKLIST))
+ return [filepath for filepath in candidates
+ if not exclude_pattern.match(filepath)]
+
+
+def _clean_existing_dir(output_root):
+ """Removes existing libchrome files.
+
+ Args:
+ output_root: Path to the output directory.
+ """
+ os.makedirs(output_root, mode=0o755, exist_ok=True)
+ for path in os.listdir(output_root):
+ target_path = os.path.join(output_root, path)
+ if (not os.path.isdir(target_path) or path in ('.git', 'libchrome_tools', 'soong')):
+ continue
+ shutil.rmtree(target_path)
+
+
+def _import_files(chromium_root, output_root):
+ """Copies files from Chromium repository into libchrome.
+
+ Args:
+ chromium_root: Path to the Chromium's repository.
+ output_root: Path to the output directory.
+ """
+ for filepath in _find_target_files(chromium_root):
+ source_path = os.path.join(chromium_root, filepath)
+ target_path = os.path.join(output_root, filepath)
+ os.makedirs(os.path.dirname(target_path), mode=0o755, exist_ok=True)
+ shutil.copy2(source_path, target_path)
+
+
+def _apply_patch_files(patch_root, output_root):
+ """Applies patches.
+
+ libchrome needs some modification from Chromium repository, e.g. supporting
+ toolchain which is not used by Chrome, or using system library rather than
+ the library checked in the Chromium repository.
+ See each *.patch file in libchrome_tools/patch/ directory for details.
+
+ Args:
+ patch_root: Path to the directory containing patch files.
+ output_root: Path to the output directory.
+ """
+ for patch_file in glob.iglob(os.path.join(patch_root, '*.patch')):
+ with open(patch_file, 'r') as f:
+ subprocess.check_call(['patch', '-p1'], stdin=f, cwd=output_root)
+
+
+def _parse_args():
+ """Parses commandline arguments."""
+ parser = argparse.ArgumentParser()
+
+ # TODO(hidehiko): Support to specify the Chromium's revision number.
+ parser.add_argument(
+ '--chromium_root',
+ help='Root directory to the local chromium repository.')
+ parser.add_argument(
+ '--output_root',
+ default=_LIBCHROME_ROOT,
+ help='Output directory, which is libchrome root directory.')
+ parser.add_argument(
+ '--patch_dir',
+ default=os.path.join(_TOOLS_DIR, 'patch'),
+ help='Directory containing patch files to be applied.')
+
+ return parser.parse_args()
+
+
+def main():
+ args = _parse_args()
+ _clean_existing_dir(args.output_root)
+ _import_files(args.chromium_root, args.output_root)
+ _apply_patch_files(args.patch_dir, args.output_root)
+ # TODO(hidehiko): Create a git commit with filling templated message.
+
+
+if __name__ == '__main__':
+ main()
diff --git a/libchrome_tools/uprev/copy_new_files.py b/libchrome_tools/uprev/copy_new_files.py
new file mode 100755
index 000000000..67da28f4a
--- /dev/null
+++ b/libchrome_tools/uprev/copy_new_files.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# 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.
+
+"""
+Utility to copy missing files from Chromium tree to Chromium OS libchrome tree
+based on hard coded rules.
+
+This utility is used to diff current HEAD against given commit in Chromium
+browser master branch, copy missing files after hard-coded filter rules and
+remove unnecessary files. libchrome original files in hard-coded filter rules
+will be untounched.
+"""
+
+import argparse
+import os
+import os.path
+import subprocess
+import sys
+
+import filters
+import utils
+
+def main():
+ # Init args
+ parser = argparse.ArgumentParser(
+ description='Copy file from given commits')
+ parser.add_argument(
+ 'commit_hash',
+ metavar='commit',
+ type=str,
+ nargs=1,
+ help='commit hash to copy files from')
+ parser.add_argument(
+ '--dry_run',
+ dest='dry_run',
+ action='store_const',
+ const=True,
+ default=False)
+ arg = parser.parse_args(sys.argv[1:])
+
+ # Read file list from HEAD and upstream commit.
+ upstream_files = utils.get_file_list(arg.commit_hash[0])
+ our_files = utils.get_file_list('HEAD')
+
+ # Calculate target file list
+ target_files = filters.filter_file(our_files, upstream_files)
+
+ # Calculate operations needed
+ ops = utils.gen_op(our_files, target_files)
+
+ if arg.dry_run:
+ # Print ops only on dry-run mode.
+ print('\n'.join(repr(x) for x in ops))
+ return
+ for op, f in ops:
+ # Ignore if op is REP because we only want to copy missing files, not to
+ # revert custom Chromium OS libchrome patch.
+ assert type(op) == utils.DiffOperations
+ if op == utils.DiffOperations.DEL:
+ subprocess.check_call(['git', 'rm', f.path]),
+ elif op == utils.DiffOperations.ADD:
+ # Create directory recursively if not exist.
+ os.makedirs(os.path.dirname(f.path), exist_ok=True)
+ # Read file by git cat-file with blob object id to avoid heavy git checkout.
+ with open(f.path, 'wb') as outfile:
+ subprocess.check_call(['git', 'cat-file', 'blob', f.id],
+ stdout=outfile)
+ # Add to git index
+ subprocess.check_call(['git', 'add', f.path])
+
+if __name__ == '__main__':
+ main()
diff --git a/libchrome_tools/uprev/dirty_uprev.py b/libchrome_tools/uprev/dirty_uprev.py
new file mode 100755
index 000000000..aa8e2bd08
--- /dev/null
+++ b/libchrome_tools/uprev/dirty_uprev.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+# 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.
+
+"""
+Utility to apply diffs between given two upstream commit hashes to current
+workspace.
+
+This utility diffs files between old_commit and new_commit, with hard-coded
+filter rules, and apply the diff to current HEAD with 3-way-merge supported.
+
+This can be used to uprev a libchrome directory when this is not git history for
+git merge to work.
+"""
+
+import argparse
+import subprocess
+import sys
+
+import filters
+import utils
+
+def main():
+ # Init args
+ parser = argparse.ArgumentParser(
+ description='Copy file from given commits')
+ parser.add_argument(
+ 'old_commit', metavar='old_commit', type=str, nargs=1,
+ help='commit hash in upstream branch or browser repository '
+ 'we want to uprev from')
+ parser.add_argument(
+ 'new_commit', metavar='new_commit', type=str, nargs=1,
+ help='commit hash in upstream branch or browser repository '
+ 'we want ot uprev to')
+ parser.add_argument(
+ '--dry_run', dest='dry_run', action='store_const', const=True, default=False)
+ parser.add_argument(
+ '--is_browser', dest='is_browser', action='store_const', const=True, default=False,
+ help='is the commit hash in browser repository')
+ arg = parser.parse_args(sys.argv[1:])
+
+ # Get old and new files.
+ old_files = utils.get_file_list(arg.old_commit[0])
+ new_files = utils.get_file_list(arg.new_commit[0])
+
+ if arg.is_browser:
+ old_files = filters.filter_file([], old_files)
+ new_files = filters.filter_file([], new_files)
+ assert filters.filter_file(old_files, []) == []
+ assert filters.filter_file(new_files, []) == []
+
+ # Generate a tree object for new files.
+ old_tree = utils.git_mktree(old_files)
+ new_tree = utils.git_mktree(new_files)
+ newroot = utils.git_commit(old_tree, [])
+ squashed = utils.git_commit(new_tree, [newroot])
+
+ # Generate patch for git am
+ patch = subprocess.check_output(['git', 'format-patch', '--stdout', newroot+b'..'+squashed])
+
+ if arg.dry_run:
+ print(patch.decode('utf-8'))
+ else:
+ subprocess.run(['git', 'am', '-3'], input=patch)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/libchrome_tools/uprev/filtered_utils.py b/libchrome_tools/uprev/filtered_utils.py
new file mode 100644
index 000000000..20639b2be
--- /dev/null
+++ b/libchrome_tools/uprev/filtered_utils.py
@@ -0,0 +1,108 @@
+# 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.
+""" Provides utilities for filtered branch handling. """
+
+import collections
+import re
+import subprocess
+
+import utils
+
+# Keyword to uniquely identify the beginning of upstream history.
+CROS_LIBCHROME_INITIAL_COMMIT = b'CrOS-Libchrome-History-Initial-Commit'
+# Keyword to identify original commit in Chromium browser repository.
+CROS_LIBCHROME_ORIGINAL_COMMIT = b'CrOS-Libchrome-Original-Commit'
+
+
+# Stores metadata required for a git commit.
+GitCommitMetadata = collections.namedtuple(
+ 'GitCommitMetadata',
+ ['parents', 'original_commits', 'tree', 'authorship', 'title', 'message', 'is_root',]
+)
+
+
+# Stores information for a commit authorship.
+GitCommitAuthorship = collections.namedtuple(
+ 'GitCommitAuthorship',
+ ['name', 'email', 'time', 'timezone',]
+)
+
+
+def get_metadata(commit_hash):
+ """Returns the metadata of the commit specified by the commit_hash.
+
+ This function parses the commit message of the commit specified by the
+ commit_hash, then returns its GitCommitMetadata instance.
+ The commit must be on the filtered branch, otherwise some metadata may be
+ omitted.
+ Returns metadata from the commit message about commit_hash on the filtered
+ branch.
+
+ Args:
+ commit_hash: the commit hash on the filtered branch.
+ """
+
+ ret = subprocess.check_output(['git', 'cat-file', 'commit',
+ commit_hash]).split(b'\n')
+ parents = []
+ tree_hash = None
+ authorship = None
+ author_re = re.compile(rb'^(.*) <(.*)> ([0-9]+) ([^ ])+$')
+ while ret:
+ line = ret[0]
+ ret = ret[1:]
+ if not line.strip():
+ # End of header. break.
+ break
+ tag, reminder = line.split(b' ', 1)
+ if tag == b'tree':
+ tree_hash = reminder
+ elif tag == b'author':
+ m = author_re.match(reminder)
+ assert m, (line, commit_hash)
+ authorship = GitCommitAuthorship(m.group(1),
+ m.group(2),
+ m.group(3),
+ m.group(4))
+ elif tag == b'parent':
+ parents.append(reminder)
+
+ title = ret[0] if ret else None
+
+ original_commits = []
+ is_root = False
+ for line in ret:
+ if line.startswith(CROS_LIBCHROME_ORIGINAL_COMMIT):
+ original_commits.append(line.split(b':')[1].strip())
+ if line == CROS_LIBCHROME_INITIAL_COMMIT:
+ is_root = True
+ msg = b'\n'.join(ret)
+ return GitCommitMetadata(parents, original_commits, tree_hash, authorship,
+ title, msg, is_root)
+
+
+def get_commits_map(commit_hash, progress_callback):
+ """Returns a map from original commit hashes to filtered commit hashes.
+
+ This function traverses the filtered branch from the commit specified by
+ commit_hash to its root, then parses each commit message and constructs the
+ map of those commits.
+
+ Args:
+ commit_hash: the commit hash on the filtered branch.
+ progress_callback: called every commit is being read. Parameters taken
+ are (idx, total_commits, current_commit)
+ """
+ commits_map = {}
+ commits_filtered_tree = utils.git_revlist(None, commit_hash)
+ for index, commit in enumerate(commits_filtered_tree, start=1):
+ if progress_callback:
+ progress_callback(index, len(commits_filtered_tree), commit[0])
+ meta = get_metadata(commit[0])
+ for original_commit in meta.original_commits:
+ commits_map[original_commit] = commit[0]
+ if meta.is_root:
+ assert 'ROOT' not in commits_map
+ commits_map['ROOT'] = commit[0]
+ return commits_map
diff --git a/libchrome_tools/uprev/filters.py b/libchrome_tools/uprev/filters.py
new file mode 100644
index 000000000..0770fbcde
--- /dev/null
+++ b/libchrome_tools/uprev/filters.py
@@ -0,0 +1,129 @@
+# 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.
+
+"""Provide filters for libchrome tools."""
+
+import re
+
+# Libchrome wants WANT but mot WANT_EXCLUDE
+# aka files matching WANT will be copied from upstream_files
+WANT = [
+ re.compile(rb'base/((?!(allocator|third_party)/).*$)'),
+ re.compile(
+ rb'base/allocator/(allocator_shim.cc|allocator_shim_override_linker_wrapped_symbols.h|allocator_shim_override_cpp_symbols.h|allocator_shim_override_libc_symbols.h|allocator_shim_default_dispatch_to_glibc.cc|allocator_shim.h|allocator_shim_default_dispatch_to_linker_wrapped_symbols.cc|allocator_extension.cc|allocator_extension.h|allocator_shim_internals.h)$'
+ ),
+ re.compile(rb'base/third_party/(dynamic_annotation|icu|nspr|valgrind)'),
+ re.compile(rb'build/(android/(gyp/util|pylib/([^/]*$|constants))|[^/]*\.(h|py)$)'),
+ re.compile(rb'mojo/'),
+ re.compile(rb'dbus/'),
+ re.compile(rb'ipc/.*(\.cc|\.h|\.mojom)$'),
+ re.compile(rb'ui/gfx/(gfx_export.h|geometry|range)'),
+ re.compile(rb'testing/[^/]*\.(cc|h)$'),
+ re.compile(rb'third_party/(jinja2|markupsafe|ply)'),
+ re.compile(
+ rb'components/(json_schema|policy/core/common/[^/]*$|policy/policy_export.h|timers)'
+ ),
+ re.compile(
+ rb'device/bluetooth/bluetooth_(common|advertisement|uuid|export)\.*(h|cc)'
+ ),
+ re.compile(
+ rb'device/bluetooth/bluez/bluetooth_service_attribute_value_bluez.(h|cc)'
+ ),
+]
+
+# WANT_EXCLUDE will be excluded from WANT
+WANT_EXCLUDE = [
+ re.compile(rb'(.*/)?BUILD.gn$'),
+ re.compile(rb'(.*/)?PRESUBMIT.py$'),
+ re.compile(rb'(.*/)?OWNERS$'),
+ re.compile(rb'(.*/)?SECURITY_OWNERS$'),
+ re.compile(rb'(.*/)?DEPS$'),
+ re.compile(rb'base/(.*/)?(ios|win|fuchsia|mac|openbsd|freebsd|nacl)/.*'),
+ re.compile(rb'.*_(ios|win|mac|fuchsia|openbsd|freebsd|nacl)[_./]'),
+ re.compile(rb'.*/(ios|win|mac|fuchsia|openbsd|freebsd|nacl)_'),
+ re.compile(rb'dbus/(test_serv(er|ice)\.cc|test_service\.h)$')
+]
+
+# Files matching KEEP should not be touched.
+# aka files matching KEEP will keep its our_files version,
+# and it will be kept even it doesn't exist in upstream.
+# KEEP-KEEP_EXCLUDE must NOT intersect with WANT-WANT_EXCLUDE
+KEEP = [
+ re.compile(
+ b'(Android.bp|BUILD.gn|crypto|libchrome_tools|MODULE_LICENSE_BSD|NOTICE|OWNERS|PRESUBMIT.cfg|soong|testrunner.cc|third_party)(/.*)?$'
+ ),
+ re.compile(rb'[^/]*$'),
+ re.compile(rb'.*buildflags.h'),
+ re.compile(rb'base/android/java/src/org/chromium/base/BuildConfig.java'),
+ re.compile(rb'testing/(gmock|gtest)/'),
+ re.compile(rb'base/third_party/(libevent|symbolize)'),
+]
+
+# KEEP_EXCLUDE wil be excluded from KEEP.
+KEEP_EXCLUDE = [
+ re.compile(rb'third_party/(jinja2|markupsafe|ply)'),
+]
+
+
+def _want_file(path):
+ """Returns whether the path wants to be a new file."""
+ wanted = False
+ for want_file_regex in WANT:
+ if want_file_regex.match(path):
+ wanted = True
+ break
+ for exclude_file_regex in WANT_EXCLUDE:
+ if exclude_file_regex.match(path):
+ wanted = False
+ break
+ return wanted
+
+
+def _keep_file(path):
+ """Returns whether the path wants to be kept untouched in local files."""
+ keep = False
+ for keep_file_regex in KEEP:
+ if keep_file_regex.match(path):
+ keep = True
+ break
+ for exclude_file_regex in KEEP_EXCLUDE:
+ if exclude_file_regex.match(path):
+ keep = False
+ break
+ return keep
+
+
+def filter_file(our_files, upstream_files):
+ """Generates a list of files we want based on hard-coded rules.
+
+ File list must be a list of GitFile.
+
+ Args:
+ our_files: files in Chromium OS libchrome repository.
+ upstream_files: files in Chromium browser repository.
+ """
+
+ files = []
+ for upstream_file in upstream_files:
+ if _want_file(upstream_file.path):
+ files.append(upstream_file)
+ for our_file in our_files:
+ if _keep_file(our_file.path):
+ files.append(our_file)
+ return files
+
+
+def filter_diff(diff):
+ """Returns a subset of diff, after running filters.
+
+ Args:
+ diff: diff to filter. diff contains list of utils.GitDiffTree
+ """
+ filtered = []
+ for change in diff:
+ path = change.file.path
+ if _want_file(path):
+ assert not _keep_file(path)
+ filtered.append(change)
+ return filtered
diff --git a/libchrome_tools/uprev/generate_filtered_tree.py b/libchrome_tools/uprev/generate_filtered_tree.py
new file mode 100755
index 000000000..63c678d9b
--- /dev/null
+++ b/libchrome_tools/uprev/generate_filtered_tree.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python3
+# 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.
+
+import argparse
+import collections
+import datetime
+import os
+import subprocess
+import sys
+import time
+
+import filtered_utils
+import filters
+import lazytree
+import utils
+
+# Use avg speed of last TIMING_DISTANCE commits.
+_TIMING_DISTANCE = 100
+# Verify the tree is consistent (diff-based, and actual) when a commit is made
+# after every _VERIFY_INTEGRITY_DISTANCE in browser repository.
+# Merge commits are always verified.
+_VERIFY_INTEGRITY_DISTANCE = 1000
+
+
+def timing(timing_deque, update=True):
+ """Returns a speed (c/s), and updates timing_deque.
+
+ Args:
+ timing_deque: a deque to store the timing of past _TIMING_DISTANCE.
+ update: adds current timestamp to timing_deque if True. It needs to set
+ to False, if it wants to be called multiple times with the current
+ timestamp.
+ """
+ first = timing_deque[0]
+ now = time.time()
+ if update:
+ timing_deque.append(now)
+ if len(timing_deque) > _TIMING_DISTANCE:
+ timing_deque.popleft()
+ return _TIMING_DISTANCE / (now - first)
+
+
+def get_start_commit_of_browser_tree(parent_filtered):
+ """Returns the last commit committed by the script, and its metadata.
+
+ Args:
+ parent_filtered: the commit hash of the tip of the filtered branch.
+ """
+ current = parent_filtered
+ while True:
+ meta = filtered_utils.get_metadata(current)
+ if meta.original_commits:
+ return current, meta
+ if not meta.parents:
+ return None, None
+ # Follow main line only
+ current = meta.parents[0]
+
+
+def find_filtered_commit(commit, commits_map):
+ """Finds the corresponding parent of a browser commit in filtered branch.
+
+ If not found, the corresponding commit of its least ancestor is used.
+
+ Args:
+ commit: commit hash in browser repository.
+ commits_map: commit hash mapping from original commit to the one in the
+ filtered branch. commits_map may be altered.
+ """
+ look_for = commit
+ while look_for not in commits_map:
+ meta = filtered_utils.get_metadata(look_for)
+ assert len(meta.parents) <= 1
+ if len(meta.parents) == 1:
+ look_for = meta.parents[0]
+ else:
+ look_for = 'ROOT'
+ commits_map[commit] = commits_map[look_for]
+ return commits_map[look_for]
+
+
+def do_commit(treehash, commithash, meta, commits_map):
+ """Makes a commit with the given arguments.
+
+ This creates a commit on the filtered branch with preserving the original
+ commiter name, email, authored timestamp and the message.
+ Also, the special annotation `CrOS-Libchrome-Original-Commit:
+ <original-commit-hash>' is appended at the end of commit message.
+ The parent commits are identified by the parents of the original commit and
+ commits_map.
+
+ Args:
+ treehash: tree object id for this commit.
+ commithash: original commit hash, used to append to commit message.
+ meta: meta data of the original commit.
+ commits_map: current known commit mapping. commits_map may be altered.
+ """
+ parents_parameters = []
+ for parent in meta.parents:
+ parents_parameters.append('-p')
+ parents_parameters.append(find_filtered_commit(parent, commits_map))
+ msg = (meta.message + b'\n\n' +
+ filtered_utils.CROS_LIBCHROME_ORIGINAL_COMMIT +
+ b': ' + commithash + b'\n')
+ return subprocess.check_output(
+ ['git', 'commit-tree'] + parents_parameters + [treehash],
+ env=dict(os.environ,
+ GIT_AUTHOR_NAME=meta.authorship.name,
+ GIT_AUTHOR_EMAIL=meta.authorship.email,
+ GIT_AUTHOR_DATE=b' '.join([meta.authorship.time,
+ meta.authorship.timezone])),
+ input=msg).strip(b'\n')
+
+
+def verify_commit(original_commit, new_tree):
+ """Verifies if new_tree is exactly original_commit after filters.
+
+ Args:
+ original_commit: commit hash in Chromium browser tree.
+ new_tree: tree hash created for upstream branch commit.
+ """
+ expected_file_list = filters.filter_file([], utils.get_file_list(original_commit))
+ assert utils.git_mktree(expected_file_list) == new_tree
+
+
+def process_commits(pending_commits, commits_map, progress_callback, commit_callback):
+ """Processes new commits in browser repository.
+
+ Returns the commit hash of the last commit made.
+
+ Args:
+ pending_commits: list of tuple (commit hash, parent hashes) to process,
+ in topological order.
+ commits_map: current known commit mapping. may be altered.
+ progress_callback: callback for every commit in pending_commits. It
+ should take (idx, total, orig_commit_hash, meta) as parameters.
+ commit_callback: callback when a commit is made to filtered branch. It
+ should take (orig_commit_hash, new_commit_hash, meta) as parameters.
+ """
+ last_commit = None
+ last_verified = -1
+ for i, commit in enumerate(pending_commits, start=1):
+ meta = filtered_utils.get_metadata(commit[0])
+ if progress_callback:
+ progress_callback(i, len(pending_commits), commit[0], meta)
+ diff_with_parent = filters.filter_diff(utils.git_difftree(
+ meta.parents[0] if meta.parents else None, commit[0]))
+ git_lazytree = lazytree.LazyTree(
+ filtered_utils.get_metadata(
+ find_filtered_commit(meta.parents[0], commits_map)).tree
+ if meta.parents else None)
+ if len(meta.parents) <= 1 and len(diff_with_parent) == 0:
+ # not merge commit AND no diff
+ if len(meta.parents) == 1 and meta.parents[0] in commits_map:
+ commits_map[commit[0]] = commits_map[meta.parents[0]]
+ continue
+ for op, f in diff_with_parent:
+ if op == utils.DiffOperations.ADD or op == utils.DiffOperations.REP:
+ git_lazytree[f.path] = f
+ elif op == utils.DiffOperations.DEL:
+ del git_lazytree[f.path]
+ treehash_after_diff_applied = git_lazytree.hash()
+ filtered_commit = do_commit(treehash_after_diff_applied, commit[0],
+ meta, commits_map)
+ if commit_callback:
+ commit_callback(commit[0], filtered_commit, meta)
+ commits_map[commit[0]] = filtered_commit
+ last_commit = filtered_commit
+ if len(meta.parents) > 1 or (i - last_verified >=
+ _VERIFY_INTEGRITY_DISTANCE):
+ # merge commit OR every _VERIFY_INTEGRITY_DISTANCE
+ last_verified = i
+ verify_commit(commit[0], treehash_after_diff_applied)
+ # Verify last commit
+ verify_commit(pending_commits[-1][0], filtered_utils.get_metadata(last_commit).tree)
+ return last_commit
+
+
+def main():
+ # Init args
+ parser = argparse.ArgumentParser(
+ description='Copy file from given commits')
+ parser.add_argument(
+ 'parent_filtered', metavar='parent_filtered', type=str, nargs=1,
+ help='commit hash in filtered branch to continue from. usually HEAD of that branch.')
+ parser.add_argument(
+ 'goal_browser', metavar='goal_browser', type=str, nargs=1,
+ help='commit hash in browser master branch.')
+ parser.add_argument(
+ '--dry_run', dest='dry_run', action='store_const', const=True, default=False)
+ arg = parser.parse_args(sys.argv[1:])
+
+ # Look for last known commit made by the script in filtered branch.
+ print('Looking for last known commit from', arg.parent_filtered[0])
+ last_known, meta_last_known = get_start_commit_of_browser_tree(
+ arg.parent_filtered[0])
+ if last_known:
+ print('Continuing from', last_known, meta_last_known)
+ else:
+ print('No known last commit')
+ print('parent on filter branch', arg.parent_filtered[0])
+
+ # Get a mapping between browser repository and filtered branch for commits
+ # in filtered branch.
+ print('reading commits details for commits mapping')
+ timing_deque = collections.deque([time.time()])
+ commits_map = filtered_utils.get_commits_map(
+ arg.parent_filtered[0],
+ lambda cur_idx, tot_cnt, cur_hash:
+ (
+ print('Reading', cur_hash, '%d/%d' % (cur_idx, tot_cnt),
+ '%f c/s' % timing(timing_deque),
+ end='\r', flush=True),
+ ))
+ if not 'ROOT' in commits_map:
+ commits_map['ROOT'] =subprocess.check_output(
+ ['git', 'commit-tree', '-p', arg.parent_filtered[0],
+ utils.git_mktree([])],
+ input=filtered_utils.CROS_LIBCHROME_INITIAL_COMMIT).strip(b'\n')
+ print()
+ print('loaded commit mapping of', len(commits_map), 'commit')
+
+ # Process newer commits in browser repository from
+ # last_known.original_commits
+ print('search for commits to filter')
+ timing_deque= collections.deque([time.time()])
+ pending_commits = utils.git_revlist(
+ meta_last_known.original_commits[0] if meta_last_known else None,
+ arg.goal_browser[0])
+ print(len(pending_commits), 'commits to process')
+ new_head = process_commits(
+ pending_commits,
+ commits_map,
+ # Print progress
+ lambda cur_idx, tot_cnt, cur_hash, cur_meta: (
+ print('Processing',
+ cur_hash, '%d/%d' % (cur_idx, tot_cnt),
+ '%f c/s' % timing(timing_deque, update=False),
+ 'eta %s' % (
+ datetime.timedelta(
+ seconds=int((tot_cnt - cur_idx) / timing(timing_deque)))),
+ cur_meta.title[:50],
+ end='\r', flush=True),
+ ),
+ # Print new commits
+ lambda orig_hash, new_hash, commit_meta:
+ print(b'%s is commited as %s: %s' % (orig_hash, new_hash,
+ commit_meta.title[:50]))
+ )
+ print()
+ print('New HEAD should be', new_head.decode('ascii'))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/libchrome_tools/uprev/lazytree.py b/libchrome_tools/uprev/lazytree.py
new file mode 100644
index 000000000..d76fa5c8c
--- /dev/null
+++ b/libchrome_tools/uprev/lazytree.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python3
+# 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.
+
+import re
+import subprocess
+
+import utils
+
+
+GIT_LSTREE_RE_LINE = re.compile(rb'^([^ ]*) ([^ ]*) ([^ ]*)\t(.*)$')
+
+
+class LazyTree:
+ """LazyTree does git mktree lazily."""
+
+ def __init__(self, treehash=None):
+ """Initializes a LazyTree.
+
+ If treehash is not None, it initializes as the tree object.
+
+ Args:
+ treehash: tree object id. please do not use a treeish, it will fail
+ later.
+ """
+ if treehash:
+ self._treehash = treehash # tree object id of current tree
+ self._subtrees = None # map from directory name to sub LazyTree
+ self._files = None # map from file naem to utils.GitFile
+ return
+ # Initialize an empty LazyTree
+ self._treehash = None
+ self._subtrees = {}
+ self._files = {}
+
+ def _loadtree(self):
+ """Loads _treehash into _subtrees and _files."""
+ if self._files is not None: # _subtrees is also not None too here.
+ return
+ output = subprocess.check_output(['git', 'ls-tree', self._treehash]).split(b'\n')
+ self._files = {}
+ self._subtrees = {}
+ for line in output:
+ if not line:
+ continue
+ m = GIT_LSTREE_RE_LINE.match(line)
+ mode, gittype, objecthash, name = m.groups()
+ assert gittype == b'blob' or gittype == b'tree'
+ assert name not in self._files and name not in self._subtrees
+ if gittype == b'blob':
+ self._files[name] = utils.GitFile(None, mode, objecthash)
+ elif gittype == b'tree':
+ self._subtrees[name] = LazyTree(objecthash)
+
+ def _remove(self, components):
+ """Removes components from self tree.
+
+ Args:
+ components: the path to remove, relative to self. Each element means
+ one level of directory tree.
+ """
+ self._loadtree()
+ self._treehash = None
+ if len(components) == 1:
+ del self._files[components[0]]
+ return
+
+ # Remove from subdirectory
+ dirname, components = components[0], components[1:]
+ subdir = self._subtrees[dirname]
+ subdir._remove(components)
+ if subdir.is_empty():
+ del self._subtrees[dirname]
+
+ def __delitem__(self, path):
+ """Removes path from self tree.
+
+ Args:
+ path: the path to remove, relative to self.
+ """
+ components = path.split(b'/')
+ self._remove(components)
+
+ def _get(self, components):
+ """Returns a file at components in utils.GitFile from self tree.
+
+ Args:
+ components: path in list instead of separated by /.
+ """
+ self._loadtree()
+ if len(components) == 1:
+ return self._files[components[0]]
+
+ dirname, components = components[0], components[1:]
+ return self._subtrees[dirname]._get(components)
+
+ def __getitem__(self, path):
+ """Returns a file at path in utils.GitFile from tree.
+
+ Args:
+ path: path of the file to read.
+ """
+ components = path.split(b'/')
+ return self._get(components)
+
+ def _set(self, components, f):
+ """Adds or replace a file.
+
+ Args:
+ components: the path to set, relative to self. Each element means
+ one level of directory tree.
+ f: a utils.GitFile object.
+ """
+
+ self._loadtree()
+ self._treehash = None
+ if len(components) == 1:
+ self._files[components[0]] = f
+ return
+
+ # Add to subdirectory
+ dirname, components = components[0], components[1:]
+ if dirname not in self._subtrees:
+ self._subtrees[dirname] = LazyTree()
+ self._subtrees[dirname]._set(components, f)
+
+ def __setitem__(self, path, f):
+ """Adds or replaces a file.
+
+ Args:
+ path: the path to set, relative to self
+ f: a utils.GitFile object
+ """
+ assert f.path.endswith(path)
+ components = path.split(b'/')
+ self._set(components, f)
+
+ def is_empty(self):
+ """Returns if self is an empty tree."""
+ return not self._subtrees and not self._files
+
+ def hash(self):
+ """Returns the hash of current tree object.
+
+ If the object doesn't exist, create it.
+ """
+ if not self._treehash:
+ self._treehash = self._mktree()
+ return self._treehash
+
+ def _mktree(self):
+ """Recreates a tree object recursively.
+
+ Lazily if subtree is unchanged.
+ """
+ keys = list(self._files.keys()) + list(self._subtrees.keys())
+ mktree_input = []
+ for name in sorted(keys):
+ file = self._files.get(name)
+ if file:
+ mktree_input.append(b'%s blob %s\t%s' % (file.mode, file.id,
+ name))
+ else:
+ mktree_input.append(
+ b'040000 tree %s\t%s' % (self._subtrees[name].hash(), name))
+ return subprocess.check_output(
+ ['git', 'mktree'],
+ input=b'\n'.join(mktree_input)).strip(b'\n')
diff --git a/libchrome_tools/uprev/reconnect_history.py b/libchrome_tools/uprev/reconnect_history.py
new file mode 100755
index 000000000..bb6040c69
--- /dev/null
+++ b/libchrome_tools/uprev/reconnect_history.py
@@ -0,0 +1,333 @@
+#!/usr/bin/env python3
+# 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.
+
+"""
+Utility to disconnect history of files from a branch, and reconnect with base on
+a different branch.
+"""
+
+import argparse
+import collections
+import subprocess
+import sys
+
+import filtered_utils
+import lazytree
+import utils
+
+
+class CommitMetadataFactory(dict):
+ """Dict-like class to read commit metadata"""
+
+ def __missing__(self, key):
+ """Reads commit metadata if missing"""
+ value = filtered_utils.get_metadata(key)
+ self.__setitem__(key, value)
+ return value
+
+
+def disconnect(source_commit, ref_commit):
+ """Creates a commit that disconnects files from source_commit.
+
+ All files existing in ref_commit will be removed from source_commit.
+
+ Args:
+ source_commit: commit hash to disconnect from.
+ ref_commit: commit hash to be a file list reference.
+ """
+ source_files = utils.get_file_list(source_commit)
+ ref_files = utils.get_file_list(ref_commit)
+ ref_files_set = set(ref.path for ref in ref_files)
+ kept_files = [ref for ref in source_files if ref.path not in ref_files_set]
+ tree = utils.git_mktree(kept_files)
+ return utils.git_commit(
+ tree, [source_commit],
+ message=b'Disconnect history from %s' % (source_commit.encode('ascii')))
+
+
+def connect_base(current_commit, base_commit):
+ """Creates a merge commit that takes files from base_commit.
+
+ Literally it's identical to git merge base_commit in current_commit.
+
+ Args:
+ current_commit: commit hashes on where to commit to.
+ base_commit: commit hashes contains file histories.
+ """
+ current_files = utils.get_file_list(current_commit)
+ base_files = utils.get_file_list(base_commit)
+ tree = utils.git_mktree(current_files + base_files)
+ return utils.git_commit(
+ tree, [current_commit, base_commit],
+ message=b'Connect history with base %s' % (base_commit.encode('ascii')))
+
+
+def blame_files(commithash, files):
+ """Blames files on givven commithash"""
+ blames = {}
+ for path in files:
+ blames[path] = utils.git_blame(commithash, path)
+ return blames
+
+
+def search_blame_line(blames, amend_commits, target_commit_hash):
+ """Searches blames matching target_commit_hash in amend_commits
+
+ Returns a map from file path to a list of tuple, each tuple has
+ len(amend_commits) + 1 elements. 0-th element is the line in blames. and
+ 1st to n-th element are corresponding lines in amend_commits blaems.
+
+ Args:
+ blames: a dict from path to list of GitBlameLine, for files blamed on
+ target_commit_hash.
+ amend_commits: a list of commit hashes to provide actual history.
+ target_commit_hash: commit hash that blames are blaemd on.
+ """
+ blames_combined = {}
+ for blame_file_path, blame_file in blames.items():
+ blames_amend = [
+ utils.git_blame(commit, blame_file_path) for commit in amend_commits
+ ]
+ blames_combined[blame_file_path] = [
+ blame_combined for blame_combined in zip(blame_file, *blames_amend)
+ if blame_combined[0].commit == target_commit_hash
+ ]
+ return blames_combined
+
+
+def get_track_from_blames(blames_combined, virtual_goal_commit, amend_commits,
+ commit_choice_cache, commit_msg_cache):
+ """Blames diffs and locate the amend commits.
+
+ Returns a tuple containing:
+ - a set of commit hashes in amend_commits tree;
+ - a line-by-line mapping for files in diff to commit hashes in
+ amend_commits tree of diffed lines.
+
+ Args:
+ blames_combined: a map from path to a list of tuple. each tuple reflect
+ one line, and has len(amend_commits)+1 elements. See more details in
+ search_blame_line.
+ virtual_goal_commit: a commit that contains no useful history for diffs.
+ amend_commits: list of HEAD commit hashes that refers to tree that can
+ amend the diffs.
+ commit_choice_cache: caches user choice on which amend commit to use.
+ commit_msg_cache: caches commit metadata.
+ """
+ blame_untracked_lines = {}
+ commits_to_track = set()
+
+ for blame_file_path, blame_lines in blames_combined.items():
+ blame_untracked_lines[blame_file_path] = []
+ for blame_line in blame_lines:
+ original_commits = tuple(
+ blame_amend.commit for blame_amend in list(blame_line)[1:])
+ chosen = commit_choice_cache.get(original_commits)
+ if chosen is None:
+ for idx, original_commit in enumerate(original_commits):
+ print('%d: %s' % (idx,
+ commit_msg_cache[original_commit].title))
+ # No validation on user_choice since no untrusted user.
+ # Also the developer can rerun if entered wrongly by accident.
+ user_choice = int(input('Choose patch: '))
+ chosen = original_commits[user_choice]
+ commit_choice_cache[original_commits] = chosen
+ commits_to_track.add(chosen)
+ blame_untracked_lines[blame_file_path].append((blame_line[0],
+ chosen))
+
+ return commits_to_track, blame_untracked_lines
+
+
+def reconstruct_file(blame_goal, blame_base, lines_to_reconstruct,
+ virtual_goal_commit):
+ """Reconstrucs a file to reflect changes in lines_to_reconstruct.
+
+ Takes lines to blame_base, and blame_goal it belongs lines_to_reconstruct.
+ It also deletes removed lines nearby.
+
+ Returns a binary for the new file content.
+
+ Args:
+ blame_goal: a list of utils.GitBlameLine blaming the file on
+ virtual_goal_commit.
+ blame_base: a list of utils.GitBlameLine blaming the file on last
+ commited commit.
+ lines_to_reconstruct: only to reconstruct these lines, instead of
+ everything in blame_goal. It is represented in a list of
+ GitBlameLine.
+ virtual_goal_commit: commit hash where blame_goal is based on.
+ """
+ idx_base, idx_goal = 0, 0
+ reconstructed_file = []
+
+ print('Changed lines are', [line.data for line in lines_to_reconstruct])
+ line_iter = iter(lines_to_reconstruct)
+ line = next(line_iter, None)
+ while idx_base < len(blame_base) or idx_goal< len(blame_goal):
+ # Both sides are idendical. We can't compare blame_base, and line
+ # directly due to blame commit difference could end up different lineno.
+ if (idx_base < len(blame_base) and
+ blame_base[idx_base].data == blame_goal[idx_goal].data and
+ blame_base[idx_base].commit == blame_goal[idx_goal].commit):
+ # We append this line if both sides are identical.
+ reconstructed_file.append(blame_base[idx_base].data)
+ idx_base += 1
+ idx_goal += 1
+ should_skip_base = False
+ elif line and blame_goal[idx_goal] == line:
+ # We append the line from goal, if blame_goal[idx_goal] is the line
+ # we're interested in.
+ reconstructed_file.append(line.data)
+ line = next(line_iter, None)
+ idx_goal += 1
+ should_skip_base = True
+ elif blame_goal[idx_goal].commit == virtual_goal_commit:
+ # We skip the line from goal, if the change in not in the commit
+ # we're interested. Thus, changed lines in other commits will not be
+ # reflected.
+ idx_goal += 1
+ else:
+ # We should skip base if we just appended some lines from goal.
+ # This would treat modified lines and append first and skip later.
+ # If we didn't append something from goal, lines from base should be
+ # preserved because the modified lines are not in the commit we're
+ # currently interested in.
+ if not should_skip_base:
+ reconstructed_file.append(blame_base[idx_base].data)
+ idx_base += 1
+
+ return b''.join([line + b'\n' for line in reconstructed_file])
+
+
+def reconstruct_files(track_commit, blame_untracked_lines, blames,
+ current_base_commit, virtual_goal_commit):
+ """Reconstructs files to reflect changes in track_commit.
+
+ Returns a map from file path to file content for reconstructed files.
+
+ Args:
+ track_commit: commit hashes to track, and reconstruct from.
+ blame_untracked_lines: a line-by-line mapping regarding selected amend
+ commits for diffs. see get_track_from_blames for more.
+ blames: a map from filename to list of utils.GitBlameLine
+ current_base_commit: commit hashes for HEAD of base that contains base
+ history + already committed amend history.
+ virtual_goal_commit: commit hash for one giant commit that has no
+ history. virtual_goal_commit is one commit ahead of
+ current_base_commit.
+ """
+ lines_to_track = collections.defaultdict(list)
+ for file, lines in blame_untracked_lines.items():
+ for line in lines:
+ if line[1] == track_commit:
+ lines_to_track[file].append(line[0])
+ constructed_files = {}
+ for current_file, current_file_lines in lines_to_track.items():
+ print('Reconstructing', current_file, 'for', track_commit)
+ blame_base = utils.git_blame(current_base_commit, current_file)
+ constructed_files[current_file] = reconstruct_file(
+ blames[current_file], blame_base, current_file_lines,
+ virtual_goal_commit)
+ return constructed_files
+
+
+def main():
+ # Init args
+ parser = argparse.ArgumentParser(description='Reconnect git history')
+ parser.add_argument(
+ 'disconnect_from',
+ metavar='disconnect_from',
+ type=str,
+ nargs=1,
+ help='disconnect history from this commit')
+ parser.add_argument(
+ 'base_commit',
+ metavar='base_commit',
+ type=str,
+ nargs=1,
+ help='base commit to use the history')
+ parser.add_argument(
+ 'amend_commits',
+ metavar='amend_commits',
+ type=str,
+ nargs='+',
+ help='commits to amend histories from base_commit')
+
+ arg = parser.parse_args(sys.argv[1:])
+ empty_commit = disconnect(arg.disconnect_from[0], arg.base_commit[0])
+ connected_base = connect_base(empty_commit, arg.base_commit[0])
+
+ commit_msg_cache = CommitMetadataFactory()
+ commit_choice_cache = {}
+ last_commit = connected_base
+ # In each iteration of the loop, it
+ # - re-create the new goal commit, (base + committed history + (one giant)
+ # uncommited history).
+ # - blame on new goal commit and tot of amend commits. map line-by-line
+ # from uncommited to past histories.
+ # - choose one of the past commits, reconstruct files to reflect changes in
+ # that commit, and create a new commits.
+ # last_commit, commit_msg_cache, commit_choice_cache will be persistent
+ # across iteratins.
+ while True:
+ # One commit is processed per iteration.
+
+ # Create virtual target commit, and its diff.
+ virtual_goal = utils.git_commit(arg.disconnect_from[0] + '^{tree}',
+ [last_commit])
+ diffs = utils.git_difftree(None, virtual_goal)
+ if not diffs:
+ print('No diffs are found between %s and goal.' %
+ (last_commit.decode('ascii'),))
+ break
+
+ blames = blame_files(virtual_goal,
+ [diff.file.path for diff in diffs])
+ blames_combined = search_blame_line(blames, arg.amend_commits,
+ virtual_goal)
+
+ commits_to_track, blame_untracked_lines = get_track_from_blames(
+ blames_combined, virtual_goal, arg.amend_commits,
+ commit_choice_cache, commit_msg_cache)
+ if not commits_to_track:
+ print('no commits to track, stopping')
+ break
+
+ # Stablely choose one commit from commits_to_track, and reconstruct it.
+ track_commit = min(commits_to_track)
+ print('Reconstructing commit %s: %s' %
+ (track_commit, commit_msg_cache[track_commit].title))
+ constructed_files = reconstruct_files(track_commit,
+ blame_untracked_lines, blames,
+ last_commit, virtual_goal)
+
+ # Mktree and commit with re-constructed_files.
+ tree = lazytree.LazyTree(filtered_utils.get_metadata(last_commit).tree)
+ for filename, filedata in constructed_files.items():
+ blob = subprocess.check_output(
+ ['git', 'hash-object', '-w', '/dev/stdin'],
+ input=filedata).strip()
+ tree[filename] = utils.GitFile(filename, tree[filename].mode, blob)
+ meta = commit_msg_cache[track_commit]
+ last_commit = utils.git_commit(
+ tree.hash(), [last_commit],
+ (meta.message + b'\n(Reconstructed from ' + track_commit + b')\n'),
+ dict(
+ GIT_AUTHOR_NAME=meta.authorship.name,
+ GIT_AUTHOR_EMAIL=meta.authorship.email,
+ GIT_AUTHOR_DATE=b' '.join(
+ [meta.authorship.time, meta.authorship.timezone])))
+ print('Reconstructed as', last_commit)
+ # Make last commit for history reconstruction.
+ print(
+ utils.git_commit(
+ filtered_utils.get_metadata(arg.disconnect_from[0]).tree,
+ [last_commit],
+ b'Finished history reconstruction\n\nRemoving unnecessary lines\n'))
+
+
+if __name__ == '__main__':
+ main()
diff --git a/libchrome_tools/uprev/utils.py b/libchrome_tools/uprev/utils.py
new file mode 100644
index 000000000..cf3c2a4b5
--- /dev/null
+++ b/libchrome_tools/uprev/utils.py
@@ -0,0 +1,261 @@
+# 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.
+
+"""Provide some basic utility functions for libchrome tools."""
+
+import collections
+import enum
+import os
+import re
+import subprocess
+
+class DiffOperations(enum.Enum):
+ """
+ Describes operations on files
+ """
+ ADD = 1
+ DEL = 2
+ REP = 3
+
+GitFile = collections.namedtuple(
+ 'GitFile',
+ ['path', 'mode', 'id',]
+)
+
+GitDiffTree = collections.namedtuple(
+ 'GitDiffTree',
+ ['op', 'file',]
+)
+
+GitBlameLine = collections.namedtuple(
+ 'GitBlameLine',
+ ['data', 'commit', 'old_line', 'new_line',]
+)
+
+
+GIT_DIFFTREE_RE_LINE = re.compile(rb'^:([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*) ([^ ]*)\t(.*)$')
+
+
+def _reverse(files):
+ """Creates a reverse map from file path to file.
+
+ Asserts if a file path exist only once in files.
+
+ Args:
+ files: list of files.
+ """
+ files_map = {}
+ for i in files:
+ if i.path in files_map:
+ assert i.path not in files_map
+ files_map[i.path] = i
+ return files_map
+
+
+def get_file_list(commit):
+ """Gets a list of the files of the commit.
+
+ Args:
+ commit: commit hash or refs.
+ """
+
+ output = subprocess.check_output(['git', 'ls-tree', '-r',
+ commit]).split(b'\n')
+ files = []
+ # Line looks like
+ # mode<space>type<space>id<tab>file name
+ # split by tab first, and by space.
+ re_line = re.compile(rb'^([^ ]*) ([^ ]*) ([^ ]*)\t(.*)$')
+ for line in output:
+ if not line:
+ continue
+ match = re_line.match(line)
+ mode, gittype, blobhash, path = match.groups()
+ if gittype == b'commit':
+ continue
+ assert gittype == b'blob', '%s\n\n%s' % (str(output), line)
+ files.append(GitFile(path, mode, blobhash))
+ return files
+
+
+def git_difftree(treeish1, treeish2):
+ """Gets diffs between treeish1 and treeish2.
+
+ It returns a list of GitDiffTree, each GitDiffTree contains an ADD, DEL or
+ REP operation and a GitFile.
+
+ Args:
+ treeish1, treeish2: treeish to diff.
+ treeish can be tree hash or commit hash. If treeish1 is None, it
+ generate difftrees with its parent.
+ """
+ out = None
+ if treeish1 is None:
+ # Remove first line since it's tree hash printed.
+ out = subprocess.check_output(['git', 'diff-tree', '-r',
+ treeish2]).split(b'\n')[1:]
+ else:
+ out = subprocess.check_output(['git', 'diff-tree', '-r',
+ treeish1, treeish2]).split(b'\n')
+ diff = []
+ for line in out:
+ if not line:
+ continue
+ match = GIT_DIFFTREE_RE_LINE.match(line)
+ oldmode, newmode, oldhash, newhash, typeofchange, path = match.groups()
+ assert typeofchange in b'ADMT', (treeish1, treeish2, line)
+ if typeofchange == b'A':
+ diff.append(
+ GitDiffTree(DiffOperations.ADD,
+ GitFile(path, newmode, newhash)))
+ elif typeofchange == b'D':
+ diff.append(
+ GitDiffTree(DiffOperations.DEL,
+ GitFile(path, oldmode, oldhash)))
+ elif typeofchange == b'M' or typeofchange == b'T':
+ diff.append(
+ GitDiffTree(DiffOperations.REP,
+ GitFile(path, newmode, newhash)))
+ else:
+ raise Exception(b"Unsupported type: " + line)
+ return diff
+
+
+def gen_op(current_files, target_files):
+ """Returns an operation list to convert files to target_files.
+
+ Generates list of operations (add/delete/replace files) if we want to
+ convert current_files in directory to target_files
+
+ Args:
+ current_files: list of files in current directory.
+ target_files: list of files we want it to be in current directory.
+ """
+ current_file_map = _reverse(current_files)
+ target_file_map = _reverse(target_files)
+ op = []
+ for i in sorted(current_file_map):
+ if i not in target_file_map:
+ op.append((DiffOperations.DEL, current_file_map[i]))
+ for i in sorted(target_file_map):
+ if i in current_file_map and current_file_map[i] != target_file_map[i]:
+ op.append((DiffOperations.REP, target_file_map[i]))
+ elif i not in current_file_map:
+ op.append((DiffOperations.ADD, target_file_map[i]))
+ return op
+
+
+def git_mktree(files):
+ """Returns a git tree object hash after mktree recursively."""
+
+ def recursive_default_dict():
+ return collections.defaultdict(recursive_default_dict)
+
+ tree = recursive_default_dict()
+ for f in files:
+ directories = f.path.split(b'/')
+ directories, filename = directories[:-1], directories[-1]
+ cwd = tree
+ for directory in directories:
+ # If cwd is a GitFile, which means a file and a directory shares the
+ # same name.
+ assert type(cwd) == collections.defaultdict
+ cwd = cwd[directory]
+ assert filename not in cwd
+ cwd[filename] = f
+
+ def _mktree(prefix, node):
+ objects = []
+ for name, val in node.items():
+ prefix.append(name)
+ if isinstance(val, collections.defaultdict):
+ tree_hash = _mktree(prefix, val)
+ objects.append(b'\t'.join(
+ [b' '.join([b'040000', b'tree', tree_hash]), name]))
+ else:
+ path = b'/'.join(prefix)
+ assert path == val.path, '%s\n%s' % (str(path), str(val.path))
+ objects.append(b'\t'.join(
+ [b' '.join([val.mode, b'blob', val.id]), name]))
+ prefix.pop(-1)
+ return subprocess.check_output(['git', 'mktree'],
+ input=b'\n'.join(objects)).strip(b'\n')
+
+ return _mktree([], tree)
+
+
+def git_commit(tree, parents, message=b"", extra_env={}):
+ """Creates a commit.
+
+ Args:
+ tree: tree object id.
+ parents: parent commit id.
+ message: commit message.
+ extra_env: extra environment variables passed to git.
+ """
+ parent_args = []
+ for parent in parents:
+ parent_args.append('-p')
+ parent_args.append(parent)
+ return subprocess.check_output(
+ ['git', 'commit-tree', tree] + parent_args,
+ input=message,
+ env=dict(os.environ, **extra_env)).strip(b'\n')
+
+
+def git_revlist(from_commit, to_commit):
+ """Returns a list of commits and their parents.
+
+ Each item in the list is a tuple, containing two elements.
+ The first element is the commit hash; the second element is a list of parent
+ commits' hash.
+ """
+
+ commits = []
+ ret = None
+ if from_commit is None:
+ ret = subprocess.check_output(['git', 'rev-list', to_commit,
+ '--topo-order', '--parents'])
+ else:
+ # b'...'.join() later requires all variable to be binary-typed.
+ if type(from_commit) == str:
+ from_commit = from_commit.encode('ascii')
+ if type(to_commit) == str:
+ to_commit = to_commit.encode('ascii')
+ commit_range = b'...'.join([from_commit, to_commit])
+ ret = subprocess.check_output(['git', 'rev-list', commit_range,
+ '--topo-order', '--parents'])
+ ret = ret.split(b'\n')
+ for line in ret:
+ if not line:
+ continue
+ hashes = line.split(b' ')
+ commits.append((hashes[0], hashes[1:]))
+ return list(reversed(commits))
+
+
+def git_blame(commit, filepath):
+ """Returns line-by-line git blame.
+
+ Return value is represented by a list of GitBlameLine.
+
+ Args:
+ commit: commit hash to blame at.
+ filepath: file to blame.
+ """
+ output = subprocess.check_output(['git', 'blame', '-p',
+ commit, filepath])
+ commit, old_line, new_line = None, None, None
+ blames = []
+ COMMIT_LINE_PREFIX = re.compile(b'^[0-9a-f]* ')
+ for line in output.split(b'\n'):
+ if not line:
+ continue
+ if line[0] == ord(b'\t'):
+ assert commit != None
+ blames.append(GitBlameLine(line[1:], commit, old_line, new_line))
+ commit, old_line, new_line = None, None, None
+ elif COMMIT_LINE_PREFIX.match(line):
+ commit, old_line, new_line = line.split(b' ', 3)[0:3]
+ return blames