diff options
author | Qijiang Fan <fqj@google.com> | 2020-07-03 13:58:01 +0900 |
---|---|---|
committer | Qijiang Fan <fqj@google.com> | 2020-07-03 14:51:37 +0900 |
commit | edddb73384356911190b33bbce56ffacedc85da2 (patch) | |
tree | 9f9a743354cc3f458775ae19e39804a553d5bbbd /libchrome_tools | |
parent | cc7f6386fd653c2da4daf75bf1584c753affd5a4 (diff) | |
parent | 2fa400214c4a9acca292b649bf060f3f87f32f14 (diff) | |
download | platform_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')
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 |