diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 16:23:34 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:37:21 +0000 |
commit | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch) | |
tree | c4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/components/crash | |
parent | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff) | |
download | qtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz |
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/crash')
36 files changed, 698 insertions, 934 deletions
diff --git a/chromium/components/crash/android/BUILD.gn b/chromium/components/crash/android/BUILD.gn index 05cc295fe4f..c61e6713ed9 100644 --- a/chromium/components/crash/android/BUILD.gn +++ b/chromium/components/crash/android/BUILD.gn @@ -6,7 +6,7 @@ import("//build/config/android/rules.gni") _jni_sources = [ "java/src/org/chromium/components/crash/browser/ChildProcessCrashObserver.java", - "java/src/org/chromium/components/crash/browser/CrashDumpManager.java", + "java/src/org/chromium/components/crash/browser/PackagePaths.java", "java/src/org/chromium/components/crash/CrashKeys.java", ] @@ -41,18 +41,6 @@ source_set("crash_android") { ] } -android_library("javatests") { - testonly = true - deps = [ - ":java", - "//base:base_java", - "//base:base_java_test_support", - "//third_party/android_support_test_runner:runner_java", - "//third_party/junit", - ] - java_files = [ "javatests/src/org/chromium/components/crash/browser/CrashDumpManagerTest.java" ] -} - source_set("unit_tests") { testonly = true sources = [ @@ -64,3 +52,31 @@ source_set("unit_tests") { "//testing/gtest", ] } + +_java_handler_jni_sources = + [ "java/src/org/chromium/components/crash/browser/CrashpadMain.java" ] + +generate_jni("java_handler_jni_headers") { + sources = _java_handler_jni_sources + jni_package = "crashpad" +} + +android_library("handler_java") { + deps = [ + "//base:base_java", + ] + java_files = _java_handler_jni_sources +} + +static_library("crashpad_main") { + sources = [ + "crashpad_main.cc", + ] + + deps = [ + ":java_handler_jni_headers", + "//base", + "//third_party/crashpad/crashpad/client", + "//third_party/crashpad/crashpad/handler", + ] +} diff --git a/chromium/components/crash/android/DEPS b/chromium/components/crash/android/DEPS index 1129c7b690d..fb4880eab96 100644 --- a/chromium/components/crash/android/DEPS +++ b/chromium/components/crash/android/DEPS @@ -1,3 +1,4 @@ include_rules = [ "+jni", -]
\ No newline at end of file + "+third_party/crashpad", +] diff --git a/chromium/components/crash/android/crashpad_main.cc b/chromium/components/crash/android/crashpad_main.cc new file mode 100644 index 00000000000..ce3d8888fb8 --- /dev/null +++ b/chromium/components/crash/android/crashpad_main.cc @@ -0,0 +1,25 @@ +// 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. + +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "jni/CrashpadMain_jni.h" +#include "third_party/crashpad/crashpad/client/client_argv_handling.h" +#include "third_party/crashpad/crashpad/handler/handler_main.h" + +namespace crashpad { + +static void JNI_CrashpadMain_CrashpadMain( + JNIEnv* env, + const base::android::JavaParamRef<jobjectArray>& j_argv) { + std::vector<std::string> argv_strings; + base::android::AppendJavaStringArrayToStringVector(env, j_argv, + &argv_strings); + + std::vector<const char*> argv; + StringVectorToCStringVector(argv_strings, &argv); + HandlerMain(argv.size() - 1, const_cast<char**>(argv.data()), nullptr); +} + +} // namespace crashpad diff --git a/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/CrashDumpManager.java b/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/CrashDumpManager.java deleted file mode 100644 index 495556181de..00000000000 --- a/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/CrashDumpManager.java +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2017 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.components.crash.browser; - -import org.chromium.base.Log; -import org.chromium.base.ThreadUtils; -import org.chromium.base.annotations.CalledByNative; - -import java.io.File; - -/** - * A Java-side bridge for continuing the upload processing for child process crash minidumps. - */ -public class CrashDumpManager { - private static final String TAG = "CrashDumpManager"; - - /** - * An interface for providing a callback that will try to upload a minidump. The callback should - * be registered on, and will be run on, the UI thread. - */ - public interface UploadMinidumpCallback { public void tryToUploadMinidump(File minidump); } - - /** - * The globally registered callback for uploading minidumps, or null if no callback has been - * registered yet. - */ - private static UploadMinidumpCallback sCallback; - - /** - * Registers a callback for uploading minidumps. May be called at most once, and only on the UI - * thread. - * - * @param callback The callback to trigger when a new minidump is generated by a child process. - */ - public static void registerUploadCallback(UploadMinidumpCallback callback) { - ThreadUtils.assertOnUiThread(); - assert sCallback == null; - sCallback = callback; - } - - /** - * Attempts to upload the specified child process minidump (or a no-op if no observer has been - * registered). - * - * @param minidumpPath The file path for the generated minidump. - */ - @CalledByNative - public static void tryToUploadMinidump(String minidumpPath) { - // The C++ code that calls into this method should be running on a background thread. It's - // important to be off the UI thread for the file operations done below. - ThreadUtils.assertOnBackgroundThread(); - - if (minidumpPath == null) { - Log.e(TAG, "Minidump path should be non-null! Bailing..."); - return; - } - - final File minidump = new File(minidumpPath); - if (!minidump.exists() || !minidump.isFile()) { - Log.e(TAG, - "Minidump path '" + minidumpPath - + "' should describe a file that exists! Bailing..."); - return; - } - - // The callback should only be accessed on the UI thread. - ThreadUtils.postOnUiThread(new Runnable() { - @Override - public void run() { - if (sCallback == null) { - Log.w(TAG, "Ignoring crash observed before a callback was registered..."); - return; - } - sCallback.tryToUploadMinidump(minidump); - } - }); - } -} diff --git a/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/CrashpadMain.java b/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/CrashpadMain.java new file mode 100644 index 00000000000..1add0b69c62 --- /dev/null +++ b/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/CrashpadMain.java @@ -0,0 +1,26 @@ +// 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. + +package org.chromium.components.crash.browser; + +import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.annotations.UsedByReflection; +import org.chromium.base.library_loader.NativeLibraries; + +@JNINamespace("crashpad") +final class CrashpadMain { + @UsedByReflection("crashpad_linux.cc") + public static void main(String[] argv) { + try { + for (String library : NativeLibraries.LIBRARIES) { + System.loadLibrary(library); + } + } catch (UnsatisfiedLinkError e) { + throw new RuntimeException(e); + } + nativeCrashpadMain(argv); + } + + private static native void nativeCrashpadMain(String[] argv); +} diff --git a/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/PackagePaths.java b/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/PackagePaths.java new file mode 100644 index 00000000000..9b621c4801b --- /dev/null +++ b/chromium/components/crash/android/java/src/org/chromium/components/crash/browser/PackagePaths.java @@ -0,0 +1,75 @@ +// 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. + +package org.chromium.components.crash.browser; + +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; +import android.os.Build; +import android.text.TextUtils; + +import org.chromium.base.BuildInfo; +import org.chromium.base.ContextUtils; +import org.chromium.base.annotations.CalledByNative; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * This class builds paths for the Chrome package. + */ +public abstract class PackagePaths { + private static final String TAG = "PackagePaths"; + + // Prevent instantiation. + private PackagePaths() {} + + /** + * @ Build paths for the chrome/webview package for the purpose of loading CrashpadMain via + * /system/bin/app_process. + */ + @CalledByNative + public static String[] makePackagePaths(String arch) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { + return new String[] {"", ""}; + } + try { + PackageManager pm = ContextUtils.getApplicationContext().getPackageManager(); + PackageInfo pi = pm.getPackageInfo( + BuildInfo.getInstance().packageName, PackageManager.GET_SHARED_LIBRARY_FILES); + + List<String> zipPaths = new ArrayList<>(10); + zipPaths.add(pi.applicationInfo.sourceDir); + if (pi.applicationInfo.splitSourceDirs != null) { + Collections.addAll(zipPaths, pi.applicationInfo.splitSourceDirs); + } + + if (pi.applicationInfo.sharedLibraryFiles != null) { + Collections.addAll(zipPaths, pi.applicationInfo.sharedLibraryFiles); + } + + List<String> libPaths = new ArrayList<>(10); + File parent = new File(pi.applicationInfo.nativeLibraryDir).getParentFile(); + if (parent != null) { + libPaths.add(new File(parent, arch).getPath()); + } + for (String zip : zipPaths) { + if (zip.endsWith(".apk")) { + libPaths.add(zip + "!/lib/" + arch); + } + } + libPaths.add(System.getProperty("java.library.path")); + libPaths.add(pi.applicationInfo.nativeLibraryDir); + + return new String[] {TextUtils.join(File.pathSeparator, zipPaths), + TextUtils.join(File.pathSeparator, libPaths)}; + + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + } +} diff --git a/chromium/components/crash/android/javatests/src/org/chromium/components/crash/browser/CrashDumpManagerTest.java b/chromium/components/crash/android/javatests/src/org/chromium/components/crash/browser/CrashDumpManagerTest.java deleted file mode 100644 index cbcbaf17edf..00000000000 --- a/chromium/components/crash/android/javatests/src/org/chromium/components/crash/browser/CrashDumpManagerTest.java +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2017 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.components.crash.browser; - -import android.support.test.InstrumentationRegistry; -import android.support.test.filters.SmallTest; - -import org.junit.After; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import org.chromium.base.ContextUtils; -import org.chromium.base.ThreadUtils; -import org.chromium.base.test.BaseJUnit4ClassRunner; -import org.chromium.base.test.util.DisabledTest; -import org.chromium.base.test.util.Feature; -import org.chromium.base.test.util.TestFileUtil; - -import java.io.File; -import java.io.IOException; - -/** - * Unittests for {@link CrashDumpManager}. - */ -@RunWith(BaseJUnit4ClassRunner.class) -public class CrashDumpManagerTest { - File mTempDir; - - @Before - public void setUp() throws Exception { - ContextUtils.initApplicationContextForTests(InstrumentationRegistry.getInstrumentation() - .getTargetContext() - .getApplicationContext()); - mTempDir = ContextUtils.getApplicationContext().getCacheDir(); - assert mTempDir.exists(); - } - - @After - public void tearDown() throws Exception { - File[] files = mTempDir.listFiles(); - if (files == null) return; - - for (File file : files) { - TestFileUtil.deleteFile(file); - } - } - - @Test - @SmallTest - @Feature({"Android-AppBase"}) - @DisabledTest // Flaky, crbug.com/725379. - public void testUploadMinidump_NoCallback() throws IOException { - File minidump = new File(mTempDir, "mini.dmp"); - Assert.assertTrue(minidump.createNewFile()); - - CrashDumpManager.tryToUploadMinidump(minidump.getAbsolutePath()); - } - - @Test - @SmallTest - @Feature({"Android-AppBase"}) - @DisabledTest // Flaky, crbug.com/725379. - public void testUploadMinidump_NullMinidumpPath() { - registerUploadCallback(new CrashDumpManager.UploadMinidumpCallback() { - @Override - public void tryToUploadMinidump(File minidump) { - Assert.fail("The callback should not be called when the minidump path is null."); - } - }); - - CrashDumpManager.tryToUploadMinidump(null); - } - - // @SmallTest - // @Feature({"Android-AppBase"}) - @Test - @DisabledTest // Flaky, crbug.com/725379. - public void testUploadMinidump_FileDoesntExist() { - registerUploadCallback(new CrashDumpManager.UploadMinidumpCallback() { - @Override - public void tryToUploadMinidump(File minidump) { - Assert.fail( - "The callback should not be called when the minidump file doesn't exist."); - } - }); - - CrashDumpManager.tryToUploadMinidump( - mTempDir.getAbsolutePath() + "/some/file/that/doesnt/exist"); - } - - @Test - @SmallTest - @Feature({"Android-AppBase"}) - @DisabledTest // Flaky, crbug.com/725379. - public void testUploadMinidump_MinidumpPathIsDirectory() throws IOException { - File directory = new File(mTempDir, "a_directory"); - Assert.assertTrue(directory.mkdir()); - - registerUploadCallback(new CrashDumpManager.UploadMinidumpCallback() { - @Override - public void tryToUploadMinidump(File minidump) { - Assert.fail( - "The callback should not be called when the minidump path is not a file."); - } - }); - - CrashDumpManager.tryToUploadMinidump(directory.getAbsolutePath()); - } - - @Test - @SmallTest - @Feature({"Android-AppBase"}) - @DisabledTest // Flaky, crbug.com/725379. - public void testUploadMinidump_MinidumpPathIsValid() throws IOException { - final File minidump = new File(mTempDir, "mini.dmp"); - Assert.assertTrue(minidump.createNewFile()); - - registerUploadCallback(new CrashDumpManager.UploadMinidumpCallback() { - @Override - public void tryToUploadMinidump(File actualMinidump) { - Assert.assertEquals("Should call the callback with the correct filename.", minidump, - actualMinidump); - } - }); - - CrashDumpManager.tryToUploadMinidump(minidump.getAbsolutePath()); - } - - /** - * A convenience wrapper that registers the upload {@param callback}, running the registration - * on the UI thread, as expected by the CrashDumpManager code. - * @param callback The callback for uploading minidumps. - */ - private static void registerUploadCallback( - final CrashDumpManager.UploadMinidumpCallback callback) { - ThreadUtils.runOnUiThreadBlocking(new Runnable() { - @Override - public void run() { - CrashDumpManager.registerUploadCallback(callback); - } - }); - } -} diff --git a/chromium/components/crash/content/app/BUILD.gn b/chromium/components/crash/content/app/BUILD.gn index 732ae72628f..5a13a51923a 100644 --- a/chromium/components/crash/content/app/BUILD.gn +++ b/chromium/components/crash/content/app/BUILD.gn @@ -36,17 +36,17 @@ static_library("app") { sources += [ "crashpad.cc" ] } - if (is_android || is_linux) { - # Want these files on both Linux and Android. + if (is_android || (is_linux && !is_chromeos)) { set_sources_assignment_filter([]) + sources += [ "crashpad_linux.cc" ] + } + + if (is_linux) { sources += [ "breakpad_linux.cc", "breakpad_linux.h", "breakpad_linux_impl.h", ] - if (!is_chromeos) { - sources += [ "crashpad_linux.cc" ] - } } defines = [ "CRASH_IMPLEMENTATION" ] @@ -61,11 +61,14 @@ static_library("app") { if (is_mac || is_win || is_android || (is_linux && !is_chromeos)) { deps += [ "//third_party/crashpad/crashpad/client", - "//third_party/crashpad/crashpad/snapshot:snapshot_api", "//third_party/crashpad/crashpad/util", ] } + if (is_android) { + deps += [ "//components/crash/android:jni_headers" ] + } + if (is_android || is_linux) { deps += [ "//base:base_static", @@ -73,9 +76,12 @@ static_library("app") { "//content/public/common:content_descriptors", "//content/public/common:result_codes", "//sandbox", - "//third_party/breakpad:client", "//third_party/crashpad/crashpad/snapshot", ] + + if (is_linux) { + deps += [ "//third_party/breakpad:client" ] + } } if (is_win) { diff --git a/chromium/components/crash/content/app/DEPS b/chromium/components/crash/content/app/DEPS index 019cf70eee9..63e5b6fcabf 100644 --- a/chromium/components/crash/content/app/DEPS +++ b/chromium/components/crash/content/app/DEPS @@ -5,6 +5,7 @@ include_rules = [ "+components/gwp_asan/crash_handler/crash_handler.h", "+content/public/common/content_descriptors.h", "+content/public/common/result_codes.h", + "+jni", "+third_party/crashpad", "+third_party/lss/linux_syscall_support.h", ] diff --git a/chromium/components/crash/content/app/breakpad_win.cc b/chromium/components/crash/content/app/breakpad_win.cc index dfb140d253e..dec9daf1fdb 100644 --- a/chromium/components/crash/content/app/breakpad_win.cc +++ b/chromium/components/crash/content/app/breakpad_win.cc @@ -24,9 +24,9 @@ #include "base/debug/dump_without_crashing.h" #include "base/environment.h" #include "base/files/file_path.h" -#include "base/macros.h" #include "base/no_destructor.h" #include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -210,7 +210,7 @@ std::wstring GetProfileType() { { PT_ROAMING, L"roaming" }, { PT_TEMPORARY, L"temporary" }, }; - for (size_t i = 0; i < arraysize(kBitNames); ++i) { + for (size_t i = 0; i < base::size(kBitNames); ++i) { const DWORD this_bit = kBitNames[i].bit; if ((profile_bits & this_bit) != 0) { profile_type.append(kBitNames[i].name); diff --git a/chromium/components/crash/content/app/crash_reporter_client.cc b/chromium/components/crash/content/app/crash_reporter_client.cc index f69c6c3ff26..b3b09cee8d6 100644 --- a/chromium/components/crash/content/app/crash_reporter_client.cc +++ b/chromium/components/crash/content/app/crash_reporter_client.cc @@ -36,7 +36,7 @@ CrashReporterClient* GetCrashReporterClient() { CrashReporterClient::CrashReporterClient() {} CrashReporterClient::~CrashReporterClient() {} -#if !defined(OS_MACOSX) && !defined(OS_WIN) +#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_ANDROID) void CrashReporterClient::SetCrashReporterClientIdFromGUID( const std::string& client_guid) {} #endif @@ -148,6 +148,14 @@ bool CrashReporterClient::ReportingIsEnforcedByPolicy(bool* breakpad_enabled) { } #if defined(OS_ANDROID) +unsigned int CrashReporterClient::GetCrashDumpPercentageForWebView() { + return 100; +} + +bool CrashReporterClient::GetBrowserProcessType(std::string* ptype) { + return false; +} + int CrashReporterClient::GetAndroidMinidumpDescriptor() { return 0; } diff --git a/chromium/components/crash/content/app/crash_reporter_client.h b/chromium/components/crash/content/app/crash_reporter_client.h index 485c2c8bf63..caebf67a7e0 100644 --- a/chromium/components/crash/content/app/crash_reporter_client.h +++ b/chromium/components/crash/content/app/crash_reporter_client.h @@ -36,14 +36,14 @@ class CrashReporterClient { CrashReporterClient(); virtual ~CrashReporterClient(); -#if !defined(OS_MACOSX) && !defined(OS_WIN) +#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_ANDROID) // Sets the crash reporting client ID, a unique identifier for the client // that is sending crash reports. After it is set, it should not be changed. // |client_guid| may either be a full GUID or a GUID that was already stripped // from its dashes. // - // On Mac OS X and Windows, this is the responsibility of Crashpad, and can - // not be set directly by the client. + // On macOS, Windows, and Android this is the responsibility of Crashpad, and + // can not be set directly by the client. virtual void SetCrashReporterClientIdFromGUID(const std::string& client_guid); #endif @@ -153,6 +153,15 @@ class CrashReporterClient { virtual bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled); #if defined(OS_ANDROID) + // Used by WebView to sample crashes without generating the unwanted dumps. If + // the returned value is less than 100, crash dumping will be sampled to that + // percentage. + virtual unsigned int GetCrashDumpPercentageForWebView(); + + // Returns true if |ptype| was set to a value to override the default `ptype` + // annotation used for the browser process. + virtual bool GetBrowserProcessType(std::string* ptype); + // Returns the descriptor key of the android minidump global descriptor. virtual int GetAndroidMinidumpDescriptor(); diff --git a/chromium/components/crash/content/app/crashpad.cc b/chromium/components/crash/content/app/crashpad.cc index 5cf5818c879..a04a4d84300 100644 --- a/chromium/components/crash/content/app/crashpad.cc +++ b/chromium/components/crash/content/app/crashpad.cc @@ -114,7 +114,8 @@ void InitializeCrashpadImpl(bool initial_client, // "relauncher" is hard-coded because it's a Chrome --type, but this // component can't see Chrome's switches. This is only used for argument // sanitization. - DCHECK(browser_process || process_type == "relauncher"); + DCHECK(browser_process || process_type == "relauncher" || + process_type == "app_shim"); #elif defined(OS_WIN) // "Chrome Installer" is the name historically used for installer binaries // as processed by the backend. @@ -264,9 +265,17 @@ bool GetUploadsEnabled() { return false; } +#if !defined(OS_ANDROID) void DumpWithoutCrashing() { CRASHPAD_SIMULATE_CRASH(); } +#endif + +#if defined(OS_LINUX) || defined(OS_ANDROID) +void CrashWithoutDumping(const std::string& message) { + crashpad::CrashpadClient::CrashWithoutDump(message); +} +#endif // defined(OS_LINUX) || defined(OS_ANDROID) void GetReports(std::vector<Report>* reports) { #if defined(OS_WIN) diff --git a/chromium/components/crash/content/app/crashpad.h b/chromium/components/crash/content/app/crashpad.h index 3c92c1631dd..c16f6b87b38 100644 --- a/chromium/components/crash/content/app/crashpad.h +++ b/chromium/components/crash/content/app/crashpad.h @@ -130,6 +130,12 @@ void RequestSingleCrashUpload(const std::string& local_id); void DumpWithoutCrashing(); +#if defined(OS_LINUX) || defined(OS_ANDROID) +// Logs message and immediately crashes the current process without triggering a +// crash dump. +void CrashWithoutDumping(const std::string& message); +#endif // defined(OS_LINUX) || defined(OS_ANDROID) + // Returns the Crashpad database path, only valid in the browser. base::FilePath GetCrashpadDatabasePath(); @@ -148,6 +154,14 @@ base::FilePath::StringType::const_pointer GetCrashpadDatabasePathImpl(); void DumpProcessWithoutCrashing(task_t task_port); #endif +#if defined(OS_ANDROID) +// This is used by WebView to generate a dump on behalf of the embedding app. +// This function can only be called from the browser process. Returns `true` on +// success. +class CrashReporterClient; +bool DumpWithoutCrashingForClient(CrashReporterClient* client); +#endif // OS_ANDROID + namespace internal { #if defined(OS_WIN) diff --git a/chromium/components/crash/content/app/crashpad_linux.cc b/chromium/components/crash/content/app/crashpad_linux.cc index 69febb07a3b..6244bfef583 100644 --- a/chromium/components/crash/content/app/crashpad_linux.cc +++ b/chromium/components/crash/content/app/crashpad_linux.cc @@ -20,39 +20,70 @@ #include "base/path_service.h" #include "base/posix/eintr_wrapper.h" #include "base/posix/global_descriptors.h" +#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" #include "components/crash/content/app/crash_reporter_client.h" #include "content/public/common/content_descriptors.h" #include "sandbox/linux/services/syscall_wrappers.h" #include "third_party/crashpad/crashpad/client/annotation.h" +#include "third_party/crashpad/crashpad/client/client_argv_handling.h" #include "third_party/crashpad/crashpad/client/crashpad_client.h" +#include "third_party/crashpad/crashpad/client/simulate_crash_linux.h" #include "third_party/crashpad/crashpad/snapshot/sanitized/sanitization_information.h" #include "third_party/crashpad/crashpad/util/linux/exception_handler_client.h" #include "third_party/crashpad/crashpad/util/linux/exception_information.h" +#include "third_party/crashpad/crashpad/util/linux/scoped_pr_set_dumpable.h" #include "third_party/crashpad/crashpad/util/misc/from_pointer_cast.h" #include "third_party/crashpad/crashpad/util/posix/signals.h" #if defined(OS_ANDROID) #include "base/android/build_info.h" #include "base/android/java_exception_reporter.h" +#include "base/android/jni_android.h" +#include "base/android/jni_array.h" +#include "base/android/jni_string.h" +#include "base/android/path_utils.h" +#include "jni/PackagePaths_jni.h" #endif // OS_ANDROID namespace crashpad { namespace { -bool SetSanitizationInfo(SanitizationInformation* info) { +bool SetSanitizationInfo(crash_reporter::CrashReporterClient* client, + SanitizationInformation* info) { const char* const* whitelist = nullptr; void* target_module = nullptr; bool sanitize_stacks = false; - crash_reporter::GetCrashReporterClient()->GetSanitizationInformation( - &whitelist, &target_module, &sanitize_stacks); + client->GetSanitizationInformation(&whitelist, &target_module, + &sanitize_stacks); info->annotations_whitelist_address = FromPointerCast<VMAddress>(whitelist); info->target_module_address = FromPointerCast<VMAddress>(target_module); info->sanitize_stacks = sanitize_stacks; return whitelist != nullptr || target_module != nullptr || sanitize_stacks; } +void SetExceptionInformation(siginfo_t* siginfo, + ucontext_t* context, + ExceptionInformation* info) { + info->siginfo_address = + FromPointerCast<decltype(info->siginfo_address)>(siginfo); + info->context_address = + FromPointerCast<decltype(info->context_address)>(context); + info->thread_id = sandbox::sys_gettid(); +} + +void SetClientInformation(ExceptionInformation* exception, + SanitizationInformation* sanitization, + ClientInformation* info) { + info->exception_information_address = + FromPointerCast<decltype(info->exception_information_address)>(exception); + + info->sanitization_information_address = + FromPointerCast<decltype(info->sanitization_information_address)>( + sanitization); +} + // A signal handler for non-browser processes in the sandbox. // Sends a message to a crashpad::CrashHandlerHost to handle the crash. class SandboxedHandler { @@ -62,12 +93,48 @@ class SandboxedHandler { return instance; } - bool Initialize() { - SetSanitizationInfo(&sanitization_); + bool Initialize(bool dump_at_crash) { + request_dump_ = dump_at_crash ? 1 : 0; + + SetSanitizationInfo(crash_reporter::GetCrashReporterClient(), + &sanitization_); server_fd_ = base::GlobalDescriptors::GetInstance()->Get( service_manager::kCrashDumpSignal); - return Signals::InstallCrashHandlers(HandleCrash, 0, nullptr); +#if defined(OS_ANDROID) + // Android's debuggerd handler on JB MR2 until OREO displays a dialog which + // is a bad user experience for child process crashes. Disable the debuggerd + // handler for user builds. crbug.com/273706 + base::android::BuildInfo* build_info = + base::android::BuildInfo::GetInstance(); + restore_previous_handler_ = + build_info->sdk_int() < base::android::SDK_VERSION_JELLY_BEAN_MR2 || + build_info->sdk_int() >= base::android::SDK_VERSION_OREO || + strcmp(build_info->build_type(), "eng") == 0 || + strcmp(build_info->build_type(), "userdebug") == 0; +#else + restore_previous_handler_ = false; +#endif + + return Signals::InstallCrashHandlers(HandleCrash, 0, &old_actions_); + } + + void HandleCrashNonFatal(int signo, siginfo_t* siginfo, void* context) { + base::ScopedFD connection; + if (ConnectToHandler(signo, &connection) == 0) { + ExceptionInformation exception_information; + SetExceptionInformation(siginfo, static_cast<ucontext_t*>(context), + &exception_information); + + ClientInformation info; + SetClientInformation(&exception_information, &sanitization_, &info); + + ScopedPrSetDumpable set_dumpable(/* may_log= */ false); + + ExceptionHandlerClient handler_client(connection.get()); + handler_client.SetCanSetPtracer(false); + handler_client.RequestCrashDump(info); + } } private: @@ -82,15 +149,23 @@ class SandboxedHandler { base::ScopedFD local_connection(fds[0]); base::ScopedFD handlers_socket(fds[1]); - iovec iov; - iov.iov_base = &signo; - iov.iov_len = sizeof(signo); + // SELinux may block the handler from setting SO_PASSCRED on this socket. + // Attempt to set it here, but the handler can still try if this fails. + int optval = 1; + socklen_t optlen = sizeof(optval); + setsockopt(handlers_socket.get(), SOL_SOCKET, SO_PASSCRED, &optval, optlen); + + iovec iov[2]; + iov[0].iov_base = &signo; + iov[0].iov_len = sizeof(signo); + iov[1].iov_base = &request_dump_; + iov[1].iov_len = sizeof(request_dump_); msghdr msg; msg.msg_name = nullptr; msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + msg.msg_iov = iov; + msg.msg_iovlen = base::size(iov); char cmsg_buf[CMSG_SPACE(sizeof(int))]; msg.msg_control = cmsg_buf; @@ -112,37 +187,21 @@ class SandboxedHandler { static void HandleCrash(int signo, siginfo_t* siginfo, void* context) { SandboxedHandler* state = Get(); - - base::ScopedFD connection; - if (state->ConnectToHandler(signo, &connection) == 0) { - ExceptionInformation exception_information; - exception_information.siginfo_address = - FromPointerCast<decltype(exception_information.siginfo_address)>( - siginfo); - exception_information.context_address = - FromPointerCast<decltype(exception_information.context_address)>( - context); - exception_information.thread_id = sandbox::sys_gettid(); - - ClientInformation info = {}; - info.exception_information_address = - FromPointerCast<decltype(info.exception_information_address)>( - &exception_information); - - info.sanitization_information_address = - FromPointerCast<decltype(info.sanitization_information_address)>( - &state->sanitization_); - - ExceptionHandlerClient handler_client(connection.get()); - handler_client.SetCanSetPtracer(false); - handler_client.RequestCrashDump(info); - } - - Signals::RestoreHandlerAndReraiseSignalOnReturn(siginfo, nullptr); + state->HandleCrashNonFatal(signo, siginfo, context); + Signals::RestoreHandlerAndReraiseSignalOnReturn( + siginfo, state->restore_previous_handler_ + ? state->old_actions_.ActionForSignal(signo) + : nullptr); } + Signals::OldActions old_actions_ = {}; SanitizationInformation sanitization_; int server_fd_; + unsigned char request_dump_; + + // true if the previously installed signal handler is restored after + // handling a crash. Otherwise SIG_DFL is restored. + bool restore_previous_handler_; DISALLOW_COPY_AND_ASSIGN(SandboxedHandler); }; @@ -169,6 +228,7 @@ void SetBuildInfoAnnotations(std::map<std::string, std::string>* annotations) { (*annotations)["android_build_id"] = info->android_build_id(); (*annotations)["android_build_fp"] = info->android_build_fp(); + (*annotations)["sdk"] = base::StringPrintf("%d", info->sdk_int()); (*annotations)["device"] = info->device(); (*annotations)["model"] = info->model(); (*annotations)["brand"] = info->brand(); @@ -186,14 +246,85 @@ void SetBuildInfoAnnotations(std::map<std::string, std::string>* annotations) { } } +#if defined(__arm__) && defined(__ARM_ARCH_7A__) +#define CURRENT_ABI "armeabi-v7a" +#elif defined(__arm__) +#define CURRENT_ABI "armeabi" +#elif defined(__i386__) +#define CURRENT_ABI "x86" +#elif defined(__mips__) +#define CURRENT_ABI "mips" +#elif defined(__x86_64__) +#define CURRENT_ABI "x86_64" +#elif defined(__aarch64__) +#define CURRENT_ABI "arm64-v8a" +#else +#error "Unsupported target abi" +#endif + +void MakePackagePaths(std::string* classpath, std::string* libpath) { + JNIEnv* env = base::android::AttachCurrentThread(); + + base::android::ScopedJavaLocalRef<jstring> arch = + base::android::ConvertUTF8ToJavaString(env, + base::StringPiece(CURRENT_ABI)); + base::android::ScopedJavaLocalRef<jobjectArray> paths = + Java_PackagePaths_makePackagePaths(env, arch); + + base::android::ConvertJavaStringToUTF8( + env, static_cast<jstring>(env->GetObjectArrayElement(paths.obj(), 0)), + classpath); + base::android::ConvertJavaStringToUTF8( + env, static_cast<jstring>(env->GetObjectArrayElement(paths.obj(), 1)), + libpath); +} + +// Copies and extends the current environment with CLASSPATH and LD_LIBRARY_PATH +// set to library paths in the APK. +bool BuildEnvironmentWithApk(std::vector<std::string>* result) { + DCHECK(result->empty()); + + std::string classpath; + std::string library_path; + MakePackagePaths(&classpath, &library_path); + + std::unique_ptr<base::Environment> env(base::Environment::Create()); + static constexpr char kClasspathVar[] = "CLASSPATH"; + std::string current_classpath; + env->GetVar(kClasspathVar, ¤t_classpath); + classpath += ":" + current_classpath; + + static constexpr char kLdLibraryPathVar[] = "LD_LIBRARY_PATH"; + std::string current_library_path; + env->GetVar(kLdLibraryPathVar, ¤t_library_path); + library_path += ":" + current_library_path; + + result->push_back("CLASSPATH=" + classpath); + result->push_back("LD_LIBRARY_PATH=" + library_path); + for (char** envp = environ; *envp != nullptr; ++envp) { + if ((strncmp(*envp, kClasspathVar, strlen(kClasspathVar)) == 0 && + (*envp)[strlen(kClasspathVar)] == '=') || + (strncmp(*envp, kLdLibraryPathVar, strlen(kLdLibraryPathVar)) == 0 && + (*envp)[strlen(kLdLibraryPathVar)] == '=')) { + continue; + } + result->push_back(*envp); + } + + return true; +} + +const char kCrashpadJavaMain[] = + "org.chromium.components.crash.browser.CrashpadMain"; + #endif // OS_ANDROID -bool BuildHandlerArgs(base::FilePath* database_path, +void BuildHandlerArgs(CrashReporterClient* crash_reporter_client, + base::FilePath* database_path, base::FilePath* metrics_path, std::string* url, std::map<std::string, std::string>* process_annotations, std::vector<std::string>* arguments) { - CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); crash_reporter_client->GetCrashDumpLocation(database_path); crash_reporter_client->GetCrashMetricsLocation(metrics_path); @@ -241,7 +372,6 @@ bool BuildHandlerArgs(base::FilePath* database_path, // so that minidumps produced by Crashpad's generate_dump tool will // contain these annotations. arguments->push_back("--monitor-self-annotation=ptype=crashpad-handler"); - return true; } bool GetHandlerPath(base::FilePath* exe_dir, base::FilePath* handler_path) { @@ -290,32 +420,57 @@ class HandlerStarter { return instance; } - base::FilePath Initialize() { - base::FilePath exe_dir; - base::FilePath handler_path; - if (!GetHandlerPath(&exe_dir, &handler_path)) { - return base::FilePath(); - } - - if (!SetLdLibraryPath(exe_dir)) { - return base::FilePath(); - } - + base::FilePath Initialize(bool dump_at_crash) { base::FilePath database_path; base::FilePath metrics_path; std::string url; std::map<std::string, std::string> process_annotations; std::vector<std::string> arguments; - if (!BuildHandlerArgs(&database_path, &metrics_path, &url, - &process_annotations, &arguments)) { - return base::FilePath(); + BuildHandlerArgs(GetCrashReporterClient(), &database_path, &metrics_path, + &url, &process_annotations, &arguments); + + base::FilePath exe_dir; + base::FilePath handler_path; + if (!GetHandlerPath(&exe_dir, &handler_path)) { + return database_path; } - if (crashpad::SetSanitizationInfo(&browser_sanitization_info_)) { + if (crashpad::SetSanitizationInfo(GetCrashReporterClient(), + &browser_sanitization_info_)) { arguments.push_back(base::StringPrintf("--sanitization-information=%p", &browser_sanitization_info_)); } +#if defined(OS_ANDROID) + if (!base::PathExists(handler_path)) { + use_java_handler_ = true; + } + + if (!dump_at_crash) { + return database_path; + } + + if (use_java_handler_) { + std::vector<std::string> env; + if (!BuildEnvironmentWithApk(&env)) { + return database_path; + } + + // TODO(jperaza): The logic for constructing an appropriate + // CLASSPATH/LD_LIBRARY_PATH won't work for Android Q+. The handler will + // need to be launched by executing the dynamic linker instead. + bool result = GetCrashpadClient().StartJavaHandlerAtCrash( + kCrashpadJavaMain, &env, database_path, metrics_path, url, + process_annotations, arguments); + DCHECK(result); + return database_path; + } +#endif + + if (!SetLdLibraryPath(exe_dir)) { + return database_path; + } + bool result = GetCrashpadClient().StartHandlerAtCrash( handler_path, database_path, metrics_path, url, process_annotations, arguments); @@ -323,24 +478,46 @@ class HandlerStarter { return database_path; } - bool StartHandlerForClient(int fd) { + bool StartHandlerForClient(CrashReporterClient* client, int fd) { + base::FilePath database_path; + base::FilePath metrics_path; + std::string url; + std::map<std::string, std::string> process_annotations; + std::vector<std::string> arguments; + BuildHandlerArgs(client, &database_path, &metrics_path, &url, + &process_annotations, &arguments); + +#if defined(OS_ANDROID) + std::string browser_ptype; + if (GetCrashReporterClient()->GetBrowserProcessType(&browser_ptype)) { + process_annotations["ptype"] = browser_ptype; + } +#endif // defined(OS_ANDROID) + base::FilePath exe_dir; base::FilePath handler_path; if (!GetHandlerPath(&exe_dir, &handler_path)) { return false; } - if (!SetLdLibraryPath(exe_dir)) { - return false; +#if defined(OS_ANDROID) + if (use_java_handler_) { + std::vector<std::string> env; + if (!BuildEnvironmentWithApk(&env)) { + return false; + } + + // TODO(jperaza): The logic for constructing an appropriate + // CLASSPATH/LD_LIBRARY_PATH won't work for Android Q+. The handler will + // need to be launched by executing the dynamic linker instead. + bool result = GetCrashpadClient().StartJavaHandlerForClient( + kCrashpadJavaMain, &env, database_path, metrics_path, url, + process_annotations, arguments, fd); + return result; } +#endif - base::FilePath database_path; - base::FilePath metrics_path; - std::string url; - std::map<std::string, std::string> process_annotations; - std::vector<std::string> arguments; - if (!BuildHandlerArgs(&database_path, &metrics_path, &url, - &process_annotations, &arguments)) { + if (!SetLdLibraryPath(exe_dir)) { return false; } @@ -354,16 +531,91 @@ class HandlerStarter { ~HandlerStarter() = delete; crashpad::SanitizationInformation browser_sanitization_info_; +#if defined(OS_ANDROID) + bool use_java_handler_ = false; +#endif DISALLOW_COPY_AND_ASSIGN(HandlerStarter); }; +bool ConnectToHandler(CrashReporterClient* client, base::ScopedFD* connection) { + int fds[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) != 0) { + PLOG(ERROR) << "socketpair"; + return false; + } + base::ScopedFD local_connection(fds[0]); + base::ScopedFD handlers_socket(fds[1]); + + if (!HandlerStarter::Get()->StartHandlerForClient(client, + handlers_socket.get())) { + return false; + } + + *connection = std::move(local_connection); + return true; +} + +bool g_is_browser = false; + } // namespace +#if defined(OS_ANDROID) +// TODO(jperaza): This might be simplified to have both the browser and child +// processes use CRASHPAD_SIMULATE_CRASH() if CrashpadClient allows injecting +// the Chromium specific SandboxedHandler. +void DumpWithoutCrashing() { + if (g_is_browser) { + CRASHPAD_SIMULATE_CRASH(); + } else { + siginfo_t siginfo; + siginfo.si_signo = crashpad::Signals::kSimulatedSigno; + siginfo.si_errno = 0; + siginfo.si_code = 0; + + ucontext_t context; + crashpad::CaptureContext(&context); + + crashpad::SandboxedHandler::Get()->HandleCrashNonFatal(siginfo.si_signo, + &siginfo, &context); + } +} +#endif + +bool DumpWithoutCrashingForClient(CrashReporterClient* client) { + base::ScopedFD connection; + if (!ConnectToHandler(client, &connection)) { + return false; + } + + siginfo_t siginfo; + siginfo.si_signo = crashpad::Signals::kSimulatedSigno; + siginfo.si_errno = 0; + siginfo.si_code = 0; + + ucontext_t context; + crashpad::CaptureContext(&context); + + crashpad::SanitizationInformation sanitization; + crashpad::SetSanitizationInfo(client, &sanitization); + + crashpad::ExceptionInformation exception; + crashpad::SetExceptionInformation(&siginfo, &context, &exception); + + crashpad::ClientInformation info; + crashpad::SetClientInformation(&exception, &sanitization, &info); + + crashpad::ScopedPrSetDumpable set_dumpable(/* may_log= */ false); + + crashpad::ExceptionHandlerClient handler_client(connection.get()); + return handler_client.RequestCrashDump(info) == 0; +} + namespace internal { bool StartHandlerForClient(int fd) { - return HandlerStarter::Get()->StartHandlerForClient(fd); + return HandlerStarter::Get()->StartHandlerForClient(GetCrashReporterClient(), + fd); } base::FilePath PlatformCrashpadInitialization( @@ -380,17 +632,26 @@ base::FilePath PlatformCrashpadInitialization( DCHECK(!embedded_handler); DCHECK(exe_path.empty()); + g_is_browser = browser_process; + + bool dump_at_crash = true; #if defined(OS_ANDROID) base::android::SetJavaExceptionCallback(SetJavaExceptionInfo); + + unsigned int dump_percentage = + GetCrashReporterClient()->GetCrashDumpPercentageForWebView(); + if (dump_percentage < 100 && rand() % 100 >= dump_percentage) { + dump_at_crash = false; + } #endif // OS_ANDROID if (browser_process) { HandlerStarter* starter = HandlerStarter::Get(); - return starter->Initialize(); + return starter->Initialize(dump_at_crash); } crashpad::SandboxedHandler* handler = crashpad::SandboxedHandler::Get(); - bool result = handler->Initialize(); + bool result = handler->Initialize(dump_at_crash); DCHECK(result); return base::FilePath(); diff --git a/chromium/components/crash/content/app/crashpad_win.cc b/chromium/components/crash/content/app/crashpad_win.cc index 8b55f0a521f..cc16c40ea32 100644 --- a/chromium/components/crash/content/app/crashpad_win.cc +++ b/chromium/components/crash/content/app/crashpad_win.cc @@ -10,6 +10,7 @@ #include "base/environment.h" #include "base/files/file_util.h" #include "base/numerics/safe_conversions.h" +#include "base/stl_util.h" #include "base/strings/string16.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" @@ -30,7 +31,7 @@ void GetPlatformCrashpadAnnotations( std::map<std::string, std::string>* annotations) { CrashReporterClient* crash_reporter_client = GetCrashReporterClient(); wchar_t exe_file[MAX_PATH] = {}; - CHECK(::GetModuleFileName(nullptr, exe_file, arraysize(exe_file))); + CHECK(::GetModuleFileName(nullptr, exe_file, base::size(exe_file))); base::string16 product_name, version, special_build, channel_name; crash_reporter_client->GetProductNameAndVersion( exe_file, &product_name, &version, &special_build, &channel_name); @@ -96,7 +97,7 @@ base::FilePath PlatformCrashpadInitialization( if (exe_file.empty()) { wchar_t exe_file_path[MAX_PATH] = {}; CHECK(::GetModuleFileName(nullptr, exe_file_path, - arraysize(exe_file_path))); + base::size(exe_file_path))); exe_file = base::FilePath(exe_file_path); } diff --git a/chromium/components/crash/content/browser/BUILD.gn b/chromium/components/crash/content/browser/BUILD.gn index d3dbf58e714..0f38a77059b 100644 --- a/chromium/components/crash/content/browser/BUILD.gn +++ b/chromium/components/crash/content/browser/BUILD.gn @@ -15,8 +15,6 @@ source_set("browser") { "child_exit_observer_android.h", "child_process_crash_observer_android.cc", "child_process_crash_observer_android.h", - "crash_dump_manager_android.cc", - "crash_dump_manager_android.h", "crash_memory_metrics_collector_android.cc", "crash_memory_metrics_collector_android.h", "crash_metrics_reporter_android.cc", @@ -28,7 +26,6 @@ source_set("browser") { "//components/crash/content/app", "//content/public/browser", "//content/public/common", - "//third_party/breakpad:client", ] if (is_linux || is_android) { @@ -39,10 +36,14 @@ source_set("browser") { "crash_handler_host_linux.cc", "crash_handler_host_linux.h", ] + } + + if (!is_chromeos) { + deps += [ "//third_party/crashpad/crashpad/client" ] + } + + if (!is_android) { deps += [ "//third_party/breakpad:client" ] - if (!is_chromeos) { - deps += [ "//third_party/crashpad/crashpad/client" ] - } } # This is not in the GYP build but this target includes breakpad client @@ -63,7 +64,6 @@ source_set("browser") { source_set("unit_tests") { testonly = true sources = [ - "crash_dump_manager_android_unittest.cc", "crash_metrics_reporter_android_unittest.cc", ] deps = [ diff --git a/chromium/components/crash/content/browser/child_exit_observer_android.cc b/chromium/components/crash/content/browser/child_exit_observer_android.cc index 5d9aa4c68f1..cd62274d372 100644 --- a/chromium/components/crash/content/browser/child_exit_observer_android.cc +++ b/chromium/components/crash/content/browser/child_exit_observer_android.cc @@ -129,20 +129,6 @@ void ChildExitObserver::OnChildExit(TerminationInfo* info) { } } -void ChildExitObserver::BrowserChildProcessStarted( - int process_host_id, - content::PosixFileDescriptorInfo* mappings) { - std::vector<Client*> registered_clients_copy; - { - base::AutoLock auto_lock(registered_clients_lock_); - for (auto& client : registered_clients_) - registered_clients_copy.push_back(client.get()); - } - for (auto* client : registered_clients_copy) { - client->OnChildStart(process_host_id, mappings); - } -} - void ChildExitObserver::BrowserChildProcessHostDisconnected( const content::ChildProcessData& data) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -230,12 +216,18 @@ void ChildExitObserver::Observe(int type, return; } const auto& iter = process_host_id_to_pid_.find(rph->GetID()); - if (iter != process_host_id_to_pid_.end()) { - if (info.pid == base::kNullProcessHandle) { - info.pid = iter->second; - } - process_host_id_to_pid_.erase(iter); + // NOTIFICATION_RENDERER_PROCESS_CLOSED corresponds to death of an underlying + // RenderProcess. NOTIFICATION_RENDERER_PROCESS_TERMINATED corresponds to when + // the RenderProcessHost's lifetime is ending. Ideally, we'd only listen to + // the former, but if the RenderProcessHost is destroyed before the + // RenderProcess, then the former is never sent. + if (iter == process_host_id_to_pid_.end()) { + return; + } + if (info.pid == base::kNullProcessHandle) { + info.pid = iter->second; } + process_host_id_to_pid_.erase(iter); OnChildExit(&info); } diff --git a/chromium/components/crash/content/browser/child_exit_observer_android.h b/chromium/components/crash/content/browser/child_exit_observer_android.h index adbccc4770d..161d2e88f04 100644 --- a/chromium/components/crash/content/browser/child_exit_observer_android.h +++ b/chromium/components/crash/content/browser/child_exit_observer_android.h @@ -12,7 +12,6 @@ #include "base/android/application_status_listener.h" #include "base/android/child_process_binding_types.h" #include "base/lazy_instance.h" -#include "base/memory/ref_counted.h" #include "base/process/process.h" #include "base/scoped_observer.h" #include "base/synchronization/lock.h" @@ -20,7 +19,6 @@ #include "content/public/browser/browser_child_process_observer.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" -#include "content/public/browser/posix_file_descriptor_info.h" #include "content/public/common/child_process_host.h" #include "content/public/common/process_type.h" #include "third_party/blink/public/common/oom_intervention/oom_intervention_types.h" @@ -46,7 +44,6 @@ class ChildExitObserver : public content::BrowserChildProcessObserver, TerminationInfo(const TerminationInfo& other); TerminationInfo& operator=(const TerminationInfo& other); - // TODO(jperaza): Not valid until Crashpad is enabled. bool is_crashed() const { return crash_signo != kInvalidSigno; } int process_host_id = content::ChildProcessHost::kInvalidUniqueID; @@ -55,7 +52,6 @@ class ChildExitObserver : public content::BrowserChildProcessObserver, base::android::ApplicationState app_state = base::android::APPLICATION_STATE_UNKNOWN; - // TODO(jperaza): Not valid until Crashpad is enabled. // The crash signal the child process received before it exited. int crash_signo = kInvalidSigno; @@ -109,9 +105,6 @@ class ChildExitObserver : public content::BrowserChildProcessObserver, // process type. class Client { public: - // OnChildStart is called on the launcher thread. - virtual void OnChildStart(int process_host_id, - content::PosixFileDescriptorInfo* mappings) = 0; // OnChildExit is called on the UI thread. // OnChildExit may be called twice for the same process. virtual void OnChildExit(const TerminationInfo& info) = 0; @@ -134,14 +127,6 @@ class ChildExitObserver : public content::BrowserChildProcessObserver, // crashpad::CrashHandlerHost::Observer void ChildReceivedCrashSignal(base::ProcessId pid, int signo) override; - // BrowserChildProcessStarted must be called from - // ContentBrowserClient::GetAdditionalMappedFilesForChildProcess - // overrides, to notify the ChildExitObserver of child process - // creation, and to allow clients to register any fd mappings they - // need. - void BrowserChildProcessStarted(int process_host_id, - content::PosixFileDescriptorInfo* mappings); - private: friend struct base::LazyInstanceTraitsBase<ChildExitObserver>; diff --git a/chromium/components/crash/content/browser/child_process_crash_observer_android.cc b/chromium/components/crash/content/browser/child_process_crash_observer_android.cc index e235ba3a06f..cd46b75b334 100644 --- a/chromium/components/crash/content/browser/child_process_crash_observer_android.cc +++ b/chromium/components/crash/content/browser/child_process_crash_observer_android.cc @@ -4,47 +4,45 @@ #include "components/crash/content/browser/child_process_crash_observer_android.h" -#include <utility> - +#include "base/android/jni_android.h" #include "base/bind.h" -#include "base/files/file_util.h" #include "base/task/post_task.h" -#include "components/crash/content/app/breakpad_linux.h" -#include "components/crash/content/browser/crash_dump_manager_android.h" +#include "base/task/task_traits.h" +#include "base/threading/scoped_blocking_call.h" +#include "components/crash/content/browser/crash_metrics_reporter_android.h" +#include "jni/ChildProcessCrashObserver_jni.h" namespace crash_reporter { -ChildProcessCrashObserver::ChildProcessCrashObserver( - const base::FilePath crash_dump_dir, - int descriptor_id) - : crash_dump_dir_(crash_dump_dir), descriptor_id_(descriptor_id) {} - -ChildProcessCrashObserver::~ChildProcessCrashObserver() {} +ChildProcessCrashObserver::ChildProcessCrashObserver() { + task_runner_ = base::CreateSequencedTaskRunnerWithTraits( + {base::MayBlock(), base::TaskPriority::BEST_EFFORT}); +} -void ChildProcessCrashObserver::OnChildStart( - int process_host_id, - content::PosixFileDescriptorInfo* mappings) { - if (!breakpad::IsCrashReporterEnabled()) - return; +ChildProcessCrashObserver::~ChildProcessCrashObserver() = default; - base::ScopedFD file( - breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFileForChild( - process_host_id)); - if (file.is_valid()) - mappings->Transfer(descriptor_id_, std::move(file)); +void ChildProcessCrashObserver::OnChildExit( + const ChildExitObserver::TerminationInfo& info) { + task_runner_->PostTask( + FROM_HERE, base::BindOnce(&ChildProcessCrashObserver::OnChildExitImpl, + base::Unretained(this), info)); } -void ChildProcessCrashObserver::OnChildExit( +void ChildProcessCrashObserver::OnChildExitImpl( const ChildExitObserver::TerminationInfo& info) { - // This might be called twice for a given child process, with a - // NOTIFICATION_RENDERER_PROCESS_TERMINATED and then with - // NOTIFICATION_RENDERER_PROCESS_CLOSED. - - base::PostTaskWithTraits( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::Bind(&breakpad::CrashDumpManager::ProcessMinidumpFileFromChild, - base::Unretained(breakpad::CrashDumpManager::GetInstance()), - crash_dump_dir_, info)); + crash_reporter::CrashMetricsReporter::GetInstance()->ChildProcessExited(info); + + if (!info.is_crashed()) { + return; + } + + base::ScopedBlockingCall sbc(base::BlockingType::WILL_BLOCK); + + // Hop over to Java to attempt to attach the logcat to the crash. This may + // fail, which is ok -- if it does, the crash will still be uploaded on the + // next browser start. + JNIEnv* env = base::android::AttachCurrentThread(); + Java_ChildProcessCrashObserver_childCrashed(env, info.pid); } } // namespace crash_reporter diff --git a/chromium/components/crash/content/browser/child_process_crash_observer_android.h b/chromium/components/crash/content/browser/child_process_crash_observer_android.h index 7710e6f9d9b..a4014592c5f 100644 --- a/chromium/components/crash/content/browser/child_process_crash_observer_android.h +++ b/chromium/components/crash/content/browser/child_process_crash_observer_android.h @@ -5,28 +5,28 @@ #ifndef COMPONENTS_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_ #define COMPONENTS_CRASH_CONTENT_BROWSER_CHILD_PROCESS_CRASH_OBSERVER_ANDROID_H_ -#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/memory/scoped_refptr.h" +#include "base/sequenced_task_runner.h" #include "components/crash/content/browser/child_exit_observer_android.h" namespace crash_reporter { +// Records metrics and initiates minidump upload in response to child process +// crashes. class ChildProcessCrashObserver : public crash_reporter::ChildExitObserver::Client { public: - ChildProcessCrashObserver(const base::FilePath crash_dump_dir, - int descriptor_id); + ChildProcessCrashObserver(); ~ChildProcessCrashObserver() override; // crash_reporter::ChildExitObserver::Client implementation: - void OnChildStart(int process_host_id, - content::PosixFileDescriptorInfo* mappings) override; void OnChildExit(const ChildExitObserver::TerminationInfo& info) override; private: - base::FilePath crash_dump_dir_; - // The id used to identify the file descriptor in the set of file - // descriptor mappings passed to the child process. - int descriptor_id_; + void OnChildExitImpl(const ChildExitObserver::TerminationInfo& info); + + scoped_refptr<base::SequencedTaskRunner> task_runner_; DISALLOW_COPY_AND_ASSIGN(ChildProcessCrashObserver); }; diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android.cc b/chromium/components/crash/content/browser/crash_dump_manager_android.cc deleted file mode 100644 index 07132888c86..00000000000 --- a/chromium/components/crash/content/browser/crash_dump_manager_android.cc +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright 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. - -#include "components/crash/content/browser/crash_dump_manager_android.h" - -#include <stdint.h> - -#include <string> - -#include "base/android/jni_android.h" -#include "base/android/jni_string.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/files/file_util.h" -#include "base/format_macros.h" -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/process/process.h" -#include "base/rand_util.h" -#include "base/stl_util.h" -#include "base/strings/stringprintf.h" -#include "base/threading/scoped_blocking_call.h" -#include "components/crash/content/app/breakpad_linux.h" -#include "components/crash/content/browser/crash_metrics_reporter_android.h" -#include "jni/CrashDumpManager_jni.h" - -namespace breakpad { - -namespace { - -base::LazyInstance<CrashDumpManager>::Leaky g_instance = - LAZY_INSTANCE_INITIALIZER; - -class DefaultUploader : public CrashDumpManager::Uploader { - public: - DefaultUploader() = default; - ~DefaultUploader() override = default; - - // CrashDumpManager::Uploader: - void TryToUploadCrashDump(const base::FilePath& crash_dump_path) override { - // Hop over to Java to attempt to attach the logcat to the crash. This may - // fail, which is ok -- if it does, the crash will still be uploaded on the - // next browser start. - JNIEnv* env = base::android::AttachCurrentThread(); - base::android::ScopedJavaLocalRef<jstring> j_dump_path = - base::android::ConvertUTF8ToJavaString(env, crash_dump_path.value()); - Java_CrashDumpManager_tryToUploadMinidump(env, j_dump_path); - } -}; - -} // namespace - -// static -CrashDumpManager* CrashDumpManager::GetInstance() { - return g_instance.Pointer(); -} - -CrashDumpManager::CrashDumpManager() - : uploader_(std::make_unique<DefaultUploader>()) {} - -CrashDumpManager::~CrashDumpManager() {} - -base::ScopedFD CrashDumpManager::CreateMinidumpFileForChild( - int process_host_id) { - base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); - base::FilePath minidump_path; - if (!base::CreateTemporaryFile(&minidump_path)) { - LOG(ERROR) << "Failed to create temporary file, crash won't be reported."; - return base::ScopedFD(); - } - - // We need read permission as the minidump is generated in several phases - // and needs to be read at some point. - int flags = base::File::FLAG_OPEN | base::File::FLAG_READ | - base::File::FLAG_WRITE; - base::File minidump_file(minidump_path, flags); - if (!minidump_file.IsValid()) { - LOG(ERROR) << "Failed to open temporary file, crash won't be reported."; - return base::ScopedFD(); - } - - SetMinidumpPath(process_host_id, minidump_path); - return base::ScopedFD(minidump_file.TakePlatformFile()); -} - -void CrashDumpManager::ProcessMinidumpFileFromChild( - base::FilePath crash_dump_dir, - const crash_reporter::ChildExitObserver::TerminationInfo& info) { - CrashDumpManager::CrashDumpStatus status = - ProcessMinidumpFileFromChildInternal(crash_dump_dir, info); - crash_reporter::CrashMetricsReporter::GetInstance()->CrashDumpProcessed( - info, status); -} - -CrashDumpManager::CrashDumpStatus -CrashDumpManager::ProcessMinidumpFileFromChildInternal( - base::FilePath crash_dump_dir, - const crash_reporter::ChildExitObserver::TerminationInfo& info) { - base::FilePath minidump_path; - // If the minidump for a given child process has already been - // processed, then there is no more work to do. - if (!GetMinidumpPath(info.process_host_id, &minidump_path)) { - return CrashDumpStatus::kMissingDump; - } - - int64_t file_size = 0; - - base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK); - if (!base::PathExists(minidump_path)) { - LOG(ERROR) << "minidump does not exist " << minidump_path.value(); - return CrashDumpStatus::kMissingDump; - } - - int r = base::GetFileSize(minidump_path, &file_size); - DCHECK(r) << "Failed to retrieve size for minidump " << minidump_path.value(); - - if (file_size == 0) { - // Empty minidump, this process did not crash. Just remove the file. - r = base::DeleteFile(minidump_path, false); - DCHECK(r) << "Failed to delete temporary minidump file " - << minidump_path.value(); - return CrashDumpStatus::kEmptyDump; - } - - // We are dealing with a valid minidump. Copy it to the crash report - // directory from where Java code will upload it later on. - if (crash_dump_dir.empty()) { - NOTREACHED() << "Failed to retrieve the crash dump directory."; - return CrashDumpStatus::kDumpProcessingFailed; - } - const uint64_t rand = base::RandUint64(); - const std::string filename = - base::StringPrintf("chromium-renderer-minidump-%016" PRIx64 ".dmp%d", - rand, info.process_host_id); - base::FilePath dest_path = crash_dump_dir.Append(filename); - r = base::Move(minidump_path, dest_path); - if (!r) { - LOG(ERROR) << "Failed to move crash dump from " << minidump_path.value() - << " to " << dest_path.value(); - base::DeleteFile(minidump_path, false); - return CrashDumpStatus::kDumpProcessingFailed; - } - VLOG(1) << "Crash minidump successfully generated: " << dest_path.value(); - - uploader_->TryToUploadCrashDump(dest_path); - return CrashDumpStatus::kValidDump; -} - -void CrashDumpManager::SetMinidumpPath(int process_host_id, - const base::FilePath& minidump_path) { - base::AutoLock auto_lock(process_host_id_to_minidump_path_lock_); - DCHECK( - !base::ContainsKey(process_host_id_to_minidump_path_, process_host_id)); - process_host_id_to_minidump_path_[process_host_id] = minidump_path; -} - -bool CrashDumpManager::GetMinidumpPath(int process_host_id, - base::FilePath* minidump_path) { - base::AutoLock auto_lock(process_host_id_to_minidump_path_lock_); - ChildProcessIDToMinidumpPath::iterator iter = - process_host_id_to_minidump_path_.find(process_host_id); - if (iter == process_host_id_to_minidump_path_.end()) { - return false; - } - *minidump_path = iter->second; - process_host_id_to_minidump_path_.erase(iter); - return true; -} - -} // namespace breakpad diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android.h b/chromium/components/crash/content/browser/crash_dump_manager_android.h deleted file mode 100644 index bc10af0c95e..00000000000 --- a/chromium/components/crash/content/browser/crash_dump_manager_android.h +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 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 COMPONENTS_CRASH_CONTENT_BROWSER_CRASH_DUMP_MANAGER_ANDROID_H_ -#define COMPONENTS_CRASH_CONTENT_BROWSER_CRASH_DUMP_MANAGER_ANDROID_H_ - -#include <map> -#include <memory> -#include <utility> - -#include "base/android/application_status_listener.h" -#include "base/files/file_path.h" -#include "base/files/platform_file.h" -#include "base/lazy_instance.h" -#include "base/memory/ref_counted.h" -#include "base/synchronization/lock.h" -#include "components/crash/content/browser/child_exit_observer_android.h" -#include "content/public/common/child_process_host.h" -#include "content/public/common/process_type.h" - -namespace breakpad { - -// This class manages the crash minidumps. -// On Android, because of process isolation, each renderer process runs with a -// different UID. As a result, we cannot generate the minidumps in the browser -// (as the browser process does not have access to some system files for the -// crashed process). So the minidump is generated in the renderer process. -// Since the isolated process cannot open files, we provide it on creation with -// a file descriptor into which to write the minidump in the event of a crash. -// This class creates these file descriptors and associates them with render -// processes and takes the appropriate action when the render process -// terminates. -class CrashDumpManager { - public: - enum class CrashDumpStatus { - // The dump for this process did not have a path set. This can happen if the - // dump was already processed or if crash dump generation is not turned on. - kMissingDump, - - // The crash dump was empty. - kEmptyDump, - - // Minidump file was found, but could not be copied to crash dir. - kDumpProcessingFailed, - - // The crash dump is valid. - kValidDump, - }; - - // Class which aids in uploading a crash dump. - class Uploader { - public: - virtual ~Uploader() = default; - - // Attempts to upload the specified child process minidump. - virtual void TryToUploadCrashDump( - const base::FilePath& crash_dump_path) = 0; - }; - - static CrashDumpManager* GetInstance(); - - void ProcessMinidumpFileFromChild( - base::FilePath crash_dump_dir, - const crash_reporter::ChildExitObserver::TerminationInfo& info); - - base::ScopedFD CreateMinidumpFileForChild(int process_host_id); - - // Careful, |uploader_| is accessed on one of the task scheduler threads. - // Tests should set this before any other threads are spawned. - void set_uploader_for_testing(std::unique_ptr<Uploader> uploader) { - DCHECK(uploader); - uploader_ = std::move(uploader); - } - - private: - friend struct base::LazyInstanceTraitsBase<CrashDumpManager>; - - CrashDumpManager(); - ~CrashDumpManager(); - - CrashDumpStatus ProcessMinidumpFileFromChildInternal( - base::FilePath crash_dump_dir, - const crash_reporter::ChildExitObserver::TerminationInfo& info); - - typedef std::map<int, base::FilePath> ChildProcessIDToMinidumpPath; - - void SetMinidumpPath(int process_host_id, - const base::FilePath& minidump_path); - bool GetMinidumpPath(int process_host_id, base::FilePath* minidump_path); - - // Should never be nullptr. - std::unique_ptr<Uploader> uploader_; - - // This map should only be accessed with its lock aquired as it is accessed - // from the PROCESS_LAUNCHER and UI threads. - base::Lock process_host_id_to_minidump_path_lock_; - ChildProcessIDToMinidumpPath process_host_id_to_minidump_path_; - - DISALLOW_COPY_AND_ASSIGN(CrashDumpManager); -}; - -} // namespace breakpad - -#endif // COMPONENTS_CRASH_CONTENT_BROWSER_CRASH_DUMP_MANAGER_ANDROID_H_ diff --git a/chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc b/chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc deleted file mode 100644 index 0b284e14a39..00000000000 --- a/chromium/components/crash/content/browser/crash_dump_manager_android_unittest.cc +++ /dev/null @@ -1,160 +0,0 @@ -// Copyright 2017 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "components/crash/content/browser/crash_dump_manager_android.h" - -#include <string> -#include <utility> - -#include "base/at_exit.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/callback.h" -#include "base/files/file.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/files/scoped_temp_dir.h" -#include "base/macros.h" -#include "base/memory/scoped_refptr.h" -#include "base/optional.h" -#include "base/run_loop.h" -#include "base/sequenced_task_runner.h" -#include "base/task/post_task.h" -#include "base/test/metrics/histogram_tester.h" -#include "base/test/scoped_task_environment.h" -#include "base/threading/sequenced_task_runner_handle.h" -#include "base/threading/thread_restrictions.h" -#include "components/crash/content/browser/crash_metrics_reporter_android.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace breakpad { - -class CrashDumpManagerTest; - -class CrashMetricsReporterObserver - : public crash_reporter::CrashMetricsReporter::Observer { - public: - CrashMetricsReporterObserver() {} - ~CrashMetricsReporterObserver() {} - - // crash_reporter::CrashMetricsReporter::Observer: - void OnCrashDumpProcessed( - int rph_id, - const crash_reporter::CrashMetricsReporter::ReportedCrashTypeSet& - reported_counts) override { - wait_run_loop_.QuitClosure().Run(); - } - - void WaitForProcessed() { wait_run_loop_.Run(); } - - private: - base::RunLoop wait_run_loop_; - DISALLOW_COPY_AND_ASSIGN(CrashMetricsReporterObserver); -}; - -class NoOpUploader : public CrashDumpManager::Uploader { - public: - NoOpUploader(scoped_refptr<base::SequencedTaskRunner> test_runner, - CrashDumpManagerTest* test_harness) - : test_runner_(std::move(test_runner)), test_harness_(test_harness) {} - ~NoOpUploader() override = default; - - // CrashDumpManager::Uploader: - void TryToUploadCrashDump(const base::FilePath& crash_dump_path) override; - - private: - scoped_refptr<base::SequencedTaskRunner> test_runner_; - CrashDumpManagerTest* test_harness_; - DISALLOW_COPY_AND_ASSIGN(NoOpUploader); -}; - -class CrashDumpManagerTest : public testing::Test { - public: - CrashDumpManagerTest() - : scoped_environment_( - base::test::ScopedTaskEnvironment::MainThreadType::UI) {} - ~CrashDumpManagerTest() override {} - - void SetUp() override { - // Initialize the manager. - ASSERT_TRUE(CrashDumpManager::GetInstance()); - CrashDumpManager::GetInstance()->set_uploader_for_testing( - std::make_unique<NoOpUploader>(base::SequencedTaskRunnerHandle::Get(), - this)); - } - - void OnUploadedCrashDump() { - dumps_uploaded_++; - if (!upload_waiter_.is_null()) - std::move(upload_waiter_).Run(); - } - - void WaitForCrashDumpsUploaded(int num_dumps) { - EXPECT_LE(num_dumps, dumps_uploaded_); - while (num_dumps < dumps_uploaded_) { - base::RunLoop run_loop; - upload_waiter_ = run_loop.QuitClosure(); - run_loop.Run(); - } - } - - static void CreateAndProcessCrashDump( - const crash_reporter::ChildExitObserver::TerminationInfo& info, - const std::string& data) { - base::ScopedFD fd = - CrashDumpManager::GetInstance()->CreateMinidumpFileForChild( - info.process_host_id); - EXPECT_TRUE(fd.is_valid()); - base::WriteFileDescriptor(fd.get(), data.data(), data.size()); - base::ScopedTempDir dump_dir; - EXPECT_TRUE(dump_dir.CreateUniqueTempDir()); - CrashDumpManager::GetInstance()->ProcessMinidumpFileFromChild( - dump_dir.GetPath(), info); - } - - protected: - int dumps_uploaded_ = 0; - - private: - base::ShadowingAtExitManager at_exit_; - base::test::ScopedTaskEnvironment scoped_environment_; - base::OnceClosure upload_waiter_; - DISALLOW_COPY_AND_ASSIGN(CrashDumpManagerTest); -}; - -void NoOpUploader::TryToUploadCrashDump(const base::FilePath& crash_dump_path) { - test_runner_->PostTask( - FROM_HERE, base::BindOnce(&CrashDumpManagerTest::OnUploadedCrashDump, - base::Unretained(test_harness_))); -} - -TEST_F(CrashDumpManagerTest, NonOomCrash) { - base::HistogramTester histogram_tester; - - CrashMetricsReporterObserver observer; - crash_reporter::CrashMetricsReporter::GetInstance()->AddObserver(&observer); - - crash_reporter::ChildExitObserver::TerminationInfo termination_info; - termination_info.process_host_id = 1; - termination_info.pid = base::kNullProcessHandle; - termination_info.process_type = content::PROCESS_TYPE_RENDERER; - termination_info.app_state = - base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES; - termination_info.normal_termination = false; - termination_info.binding_state = base::android::ChildBindingState::STRONG; - termination_info.was_killed_intentionally_by_browser = false; - termination_info.was_oom_protected_status = true; - base::PostTaskWithTraits( - FROM_HERE, {base::MayBlock(), base::TaskPriority::BEST_EFFORT}, - base::BindOnce(&CrashDumpManagerTest::CreateAndProcessCrashDump, - termination_info, "Some non-empty crash data")); - observer.WaitForProcessed(); - - histogram_tester.ExpectUniqueSample( - "Tab.RendererDetailedExitStatus", - crash_reporter::CrashMetricsReporter::VALID_MINIDUMP_WHILE_RUNNING, 1); - WaitForCrashDumpsUploaded(1); -} - -} // namespace breakpad diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.cc b/chromium/components/crash/content/browser/crash_handler_host_linux.cc index 815bf788f28..13cf0e84db6 100644 --- a/chromium/components/crash/content/browser/crash_handler_host_linux.cc +++ b/chromium/components/crash/content/browser/crash_handler_host_linux.cc @@ -28,6 +28,7 @@ #include "base/path_service.h" #include "base/posix/eintr_wrapper.h" #include "base/rand_util.h" +#include "base/stl_util.h" #include "base/strings/string_util.h" #include "base/strings/stringprintf.h" #include "base/task/post_task.h" @@ -53,6 +54,7 @@ #if !defined(OS_CHROMEOS) #include "components/crash/content/app/crashpad.h" #include "third_party/crashpad/crashpad/client/crashpad_client.h" // nogncheck +#include "third_party/crashpad/crashpad/util/posix/signals.h" // nogncheck #endif using content::BrowserThread; @@ -116,7 +118,6 @@ CrashHandlerHostLinux::CrashHandlerHostLinux(const std::string& process_type, upload_(upload), #endif fd_watch_controller_(FROM_HERE), - shutting_down_(false), blocking_task_runner_(base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::USER_VISIBLE})) { int fds[2]; @@ -228,10 +229,9 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { const ssize_t msg_size = HANDLE_EINTR(recvmsg(browser_socket_, &msg, 0)); if (msg_size < 0) { - LOG(ERROR) << "Error reading from death signal socket. Crash dumping" - << " is disabled." - << " msg_size:" << msg_size - << " errno:" << errno; + PLOG(ERROR) << "Error reading from death signal socket. Crash dumping" + << " is disabled." + << " msg_size:" << msg_size; fd_watch_controller_.StopWatchingFileDescriptor(); return; } @@ -491,12 +491,12 @@ void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { // If we are quitting and there are crash dumps in the queue, turn them into // no-ops. - shutting_down_ = true; + shutting_down_.Set(); uploader_thread_->Stop(); } bool CrashHandlerHostLinux::IsShuttingDown() const { - return shutting_down_; + return shutting_down_.IsSet(); } } // namespace breakpad @@ -569,15 +569,18 @@ void CrashHandlerHost::Init() { bool CrashHandlerHost::ReceiveClientMessage(int client_fd, base::ScopedFD* handler_fd) { int signo; - iovec iov; - iov.iov_base = &signo; - iov.iov_len = sizeof(signo); + unsigned char request_dump; + iovec iov[2]; + iov[0].iov_base = &signo; + iov[0].iov_len = sizeof(signo); + iov[1].iov_base = &request_dump; + iov[1].iov_len = sizeof(request_dump); msghdr msg; msg.msg_name = nullptr; msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; + msg.msg_iov = iov; + msg.msg_iovlen = base::size(iov); char cmsg_buf[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(ucred))]; msg.msg_control = cmsg_buf; @@ -615,7 +618,17 @@ bool CrashHandlerHost::ReceiveClientMessage(int client_fd, return false; } - NotifyCrashSignalObservers(child_pid, signo); + if (signo != crashpad::Signals::kSimulatedSigno) { + NotifyCrashSignalObservers(child_pid, signo); + } + +#if defined(OS_ANDROID) + if (!request_dump) { + return false; + } +#else + DCHECK(request_dump); +#endif handler_fd->reset(child_fd.release()); return true; diff --git a/chromium/components/crash/content/browser/crash_handler_host_linux.h b/chromium/components/crash/content/browser/crash_handler_host_linux.h index 916005283a6..18f156cb860 100644 --- a/chromium/components/crash/content/browser/crash_handler_host_linux.h +++ b/chromium/components/crash/content/browser/crash_handler_host_linux.h @@ -17,6 +17,7 @@ #include "base/message_loop/message_loop_current.h" #include "base/message_loop/message_pump_for_io.h" #include "base/process/process_handle.h" +#include "base/synchronization/atomic_flag.h" #include "base/synchronization/lock.h" #include "build/build_config.h" @@ -108,7 +109,7 @@ class CrashHandlerHostLinux base::MessagePumpForIO::FdWatchController fd_watch_controller_; std::unique_ptr<base::Thread> uploader_thread_; - bool shutting_down_; + base::AtomicFlag shutting_down_; scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_; diff --git a/chromium/components/crash/content/browser/crash_metrics_reporter_android.cc b/chromium/components/crash/content/browser/crash_metrics_reporter_android.cc index bf6d85a219b..9ddeee9f2f0 100644 --- a/chromium/components/crash/content/browser/crash_metrics_reporter_android.cc +++ b/chromium/components/crash/content/browser/crash_metrics_reporter_android.cc @@ -8,7 +8,7 @@ #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" #include "base/optional.h" -#include "components/crash/content/browser/crash_dump_manager_android.h" +#include "base/rand_util.h" namespace crash_reporter { namespace { @@ -108,35 +108,17 @@ void CrashMetricsReporter::RemoveObserver( async_observers_->RemoveObserver(observer); } -void CrashMetricsReporter::CrashDumpProcessed( - const ChildExitObserver::TerminationInfo& info, - breakpad::CrashDumpManager::CrashDumpStatus status) { +void CrashMetricsReporter::ChildProcessExited( + const ChildExitObserver::TerminationInfo& info) { ReportedCrashTypeSet reported_counts; - - // Avoid duplicating processing for the same process. - if (status == breakpad::CrashDumpManager::CrashDumpStatus::kMissingDump) - return; - - bool has_valid_dump = false; - switch (status) { - case breakpad::CrashDumpManager::CrashDumpStatus::kMissingDump: - NOTREACHED(); - break; - case breakpad::CrashDumpManager::CrashDumpStatus::kEmptyDump: - has_valid_dump = false; - break; - case breakpad::CrashDumpManager::CrashDumpStatus::kValidDump: - case breakpad::CrashDumpManager::CrashDumpStatus::kDumpProcessingFailed: - has_valid_dump = true; - break; - } + const bool crashed = info.is_crashed(); const bool app_foreground = info.app_state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES || info.app_state == base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES; const bool intentional_kill = info.was_killed_intentionally_by_browser; const bool android_oom_kill = !info.was_killed_intentionally_by_browser && - !has_valid_dump && !info.normal_termination; + !crashed && !info.normal_termination; const bool renderer_visible = info.renderer_has_visible_clients; const bool renderer_subframe = info.renderer_was_subframe; const bool renderer_allocation_failed = @@ -170,7 +152,7 @@ void CrashMetricsReporter::CrashDumpProcessed( if (info.process_type == content::PROCESS_TYPE_RENDERER && app_foreground) { if (renderer_visible) { - if (has_valid_dump) { + if (crashed) { ReportCrashCount( renderer_subframe ? ProcessedCrashCounts::kRendererForegroundVisibleSubframeCrash @@ -219,7 +201,7 @@ void CrashMetricsReporter::CrashDumpProcessed( vm_size_kb / 1024); } } - } else if (!has_valid_dump) { + } else if (!crashed) { // Record stats when renderer is not visible, but the process has oom // protected bindings. This case occurs when a tab is switched or closed, // the bindings are updated later than visibility on web contents. @@ -267,7 +249,7 @@ void CrashMetricsReporter::CrashDumpProcessed( &reported_counts); } - if (has_valid_dump) { + if (crashed) { if (info.process_type == content::PROCESS_TYPE_RENDERER) { ReportCrashCount(ProcessedCrashCounts::kRendererCrashAll, &reported_counts); @@ -305,7 +287,7 @@ void CrashMetricsReporter::CrashDumpProcessed( info.remaining_process_with_strong_binding, 20); } - ReportLegacyCrashUma(info, has_valid_dump); + ReportLegacyCrashUma(info, crashed); NotifyObservers(info.process_host_id, reported_counts); } diff --git a/chromium/components/crash/content/browser/crash_metrics_reporter_android.h b/chromium/components/crash/content/browser/crash_metrics_reporter_android.h index f098ac21f2b..c2ededf3f4c 100644 --- a/chromium/components/crash/content/browser/crash_metrics_reporter_android.h +++ b/chromium/components/crash/content/browser/crash_metrics_reporter_android.h @@ -8,7 +8,6 @@ #include "base/containers/flat_set.h" #include "base/observer_list_threadsafe.h" #include "components/crash/content/browser/child_exit_observer_android.h" -#include "components/crash/content/browser/crash_dump_manager_android.h" namespace crash_reporter { @@ -75,8 +74,8 @@ class CrashMetricsReporter { void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); - void CrashDumpProcessed(const ChildExitObserver::TerminationInfo& info, - breakpad::CrashDumpManager::CrashDumpStatus status); + void ChildProcessExited( + const crash_reporter::ChildExitObserver::TerminationInfo& info); private: CrashMetricsReporter(); diff --git a/chromium/components/crash/content/browser/crash_metrics_reporter_android_unittest.cc b/chromium/components/crash/content/browser/crash_metrics_reporter_android_unittest.cc index 380b9abbec6..a01347fb043 100644 --- a/chromium/components/crash/content/browser/crash_metrics_reporter_android_unittest.cc +++ b/chromium/components/crash/content/browser/crash_metrics_reporter_android_unittest.cc @@ -4,6 +4,8 @@ #include "components/crash/content/browser/crash_metrics_reporter_android.h" +#include <signal.h> + #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/run_loop.h" @@ -47,20 +49,6 @@ class CrashMetricsReporterTest : public testing::Test { base::test::ScopedTaskEnvironment::MainThreadType::UI) {} ~CrashMetricsReporterTest() override {} - static void CreateAndProcessCrashDump( - const ChildExitObserver::TerminationInfo& info, - const std::string& data) { - base::ScopedFD fd = - breakpad::CrashDumpManager::GetInstance()->CreateMinidumpFileForChild( - info.process_host_id); - EXPECT_TRUE(fd.is_valid()); - base::WriteFileDescriptor(fd.get(), data.data(), data.size()); - base::ScopedTempDir dump_dir; - EXPECT_TRUE(dump_dir.CreateUniqueTempDir()); - breakpad::CrashDumpManager::GetInstance()->ProcessMinidumpFileFromChild( - dump_dir.GetPath(), info); - } - protected: blink::OomInterventionMetrics InterventionMetrics(bool allocation_failed) { blink::OomInterventionMetrics metrics; @@ -81,9 +69,7 @@ class CrashMetricsReporterTest : public testing::Test { CrashMetricsReporterObserver crash_dump_observer; CrashMetricsReporter::GetInstance()->AddObserver(&crash_dump_observer); - CrashMetricsReporter::GetInstance()->CrashDumpProcessed( - termination_info, - breakpad::CrashDumpManager::CrashDumpStatus::kEmptyDump); + CrashMetricsReporter::GetInstance()->ChildProcessExited(termination_info); crash_dump_observer.WaitForProcessed(); EXPECT_EQ(expected_crash_types, crash_dump_observer.recorded_crash_types()); @@ -180,6 +166,7 @@ TEST_F(CrashMetricsReporterTest, UtilityProcessAll) { termination_info.process_type = content::PROCESS_TYPE_UTILITY; termination_info.app_state = base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES; + termination_info.crash_signo = SIGSEGV; termination_info.normal_termination = false; termination_info.binding_state = base::android::ChildBindingState::STRONG; termination_info.was_killed_intentionally_by_browser = false; @@ -189,9 +176,7 @@ TEST_F(CrashMetricsReporterTest, UtilityProcessAll) { CrashMetricsReporterObserver crash_dump_observer; CrashMetricsReporter::GetInstance()->AddObserver(&crash_dump_observer); - CrashMetricsReporter::GetInstance()->CrashDumpProcessed( - termination_info, - breakpad::CrashDumpManager::CrashDumpStatus::kValidDump); + CrashMetricsReporter::GetInstance()->ChildProcessExited(termination_info); crash_dump_observer.WaitForProcessed(); EXPECT_EQ(CrashMetricsReporter::ReportedCrashTypeSet( @@ -329,6 +314,7 @@ TEST_F(CrashMetricsReporterTest, RendererForegroundCrash) { termination_info.process_type = content::PROCESS_TYPE_RENDERER; termination_info.app_state = base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES; + termination_info.crash_signo = SIGSEGV; termination_info.normal_termination = true; termination_info.binding_state = base::android::ChildBindingState::STRONG; termination_info.was_killed_intentionally_by_browser = true; @@ -338,9 +324,7 @@ TEST_F(CrashMetricsReporterTest, RendererForegroundCrash) { CrashMetricsReporterObserver crash_dump_observer; CrashMetricsReporter::GetInstance()->AddObserver(&crash_dump_observer); - CrashMetricsReporter::GetInstance()->CrashDumpProcessed( - termination_info, - breakpad::CrashDumpManager::CrashDumpStatus::kValidDump); + CrashMetricsReporter::GetInstance()->ChildProcessExited(termination_info); crash_dump_observer.WaitForProcessed(); EXPECT_EQ( diff --git a/chromium/components/crash/content/tools/generate_breakpad_symbols.py b/chromium/components/crash/content/tools/generate_breakpad_symbols.py index 2032f1991ad..c926de336a8 100755 --- a/chromium/components/crash/content/tools/generate_breakpad_symbols.py +++ b/chromium/components/crash/content/tools/generate_breakpad_symbols.py @@ -12,6 +12,7 @@ platforms is planned. import collections import errno import glob +import multiprocessing import optparse import os import Queue @@ -22,7 +23,7 @@ import sys import threading -CONCURRENT_TASKS=4 +CONCURRENT_TASKS=multiprocessing.cpu_count() # The BINARY_INFO tuple describes a binary as dump_syms identifies it. BINARY_INFO = collections.namedtuple('BINARY_INFO', @@ -60,7 +61,7 @@ def Resolve(path, exe_path, loader_path, rpaths): def GetSharedLibraryDependenciesLinux(binary): - """Return absolute paths to all shared library dependecies of the binary. + """Return absolute paths to all shared library dependencies of the binary. This implementation assumes that we're running on a Linux system.""" # TODO(thakis): Figure out how to make this work for android @@ -72,7 +73,7 @@ def GetSharedLibraryDependenciesLinux(binary): for line in ldd.splitlines(): m = lib_re.match(line) if m: - result.append(m.group(1)) + result.append(os.path.abspath(m.group(1))) return result @@ -106,7 +107,7 @@ def GetDeveloperDirMac(): def GetSharedLibraryDependenciesMac(binary, exe_path): - """Return absolute paths to all shared library dependecies of the binary. + """Return absolute paths to all shared library dependencies of the binary. This implementation assumes that we're running on a Mac system.""" # realpath() serves two purposes: @@ -164,7 +165,7 @@ def GetSharedLibraryDependenciesMac(binary, exe_path): def GetSharedLibraryDependencies(options, binary, exe_path): - """Return absolute paths to all shared library dependecies of the binary.""" + """Return absolute paths to all shared library dependencies of the binary.""" deps = [] if sys.platform.startswith('linux'): deps = GetSharedLibraryDependenciesLinux(binary) @@ -183,6 +184,29 @@ def GetSharedLibraryDependencies(options, binary, exe_path): return result +def GetTransitiveDependencies(options): + """Return absolute paths to the transitive closure of all shared library + dependencies of the binary, along with the binary itself.""" + binary = os.path.abspath(options.binary) + exe_path = os.path.dirname(binary) + if sys.platform.startswith('linux'): + # 'ldd' returns all transitive dependencies for us. + deps = set(GetSharedLibraryDependencies(options, binary, exe_path)) + deps.add(binary) + return list(deps) + if sys.platform == 'darwin': + binaries = set([binary]) + queue = [binary] + while queue: + deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path) + new_deps = set(deps) - binaries + binaries |= new_deps + queue.extend(list(new_deps)) + return binaries + print "Platform not supported." + sys.exit(1) + + def mkdir_p(path): """Simulates mkdir -p.""" try: @@ -328,14 +352,7 @@ def main(): return 1 # Build the transitive closure of all dependencies. - binaries = set([options.binary]) - queue = [options.binary] - exe_path = os.path.dirname(options.binary) - while queue: - deps = GetSharedLibraryDependencies(options, queue.pop(0), exe_path) - new_deps = set(deps) - binaries - binaries |= new_deps - queue.extend(list(new_deps)) + binaries = GetTransitiveDependencies(options) GenerateSymbols(options, binaries) diff --git a/chromium/components/crash/core/browser/crashes_ui_util.cc b/chromium/components/crash/core/browser/crashes_ui_util.cc index 78fa705f2e3..b714115c572 100644 --- a/chromium/components/crash/core/browser/crashes_ui_util.cc +++ b/chromium/components/crash/core/browser/crashes_ui_util.cc @@ -9,7 +9,7 @@ #include <vector> #include "base/i18n/time_formatting.h" -#include "base/macros.h" +#include "base/stl_util.h" #include "base/values.h" #include "components/strings/grit/components_chromium_strings.h" #include "components/strings/grit/components_strings.h" @@ -38,7 +38,7 @@ const CrashesUILocalizedString kCrashesUILocalizedStrings[] = { }; const size_t kCrashesUILocalizedStringsCount = - arraysize(kCrashesUILocalizedStrings); + base::size(kCrashesUILocalizedStrings); const char kCrashesUICrashesJS[] = "crashes.js"; const char kCrashesUIRequestCrashList[] = "requestCrashList"; diff --git a/chromium/components/crash/core/common/BUILD.gn b/chromium/components/crash/core/common/BUILD.gn index c8e02ebf852..81912a5691c 100644 --- a/chromium/components/crash/core/common/BUILD.gn +++ b/chromium/components/crash/core/common/BUILD.gn @@ -20,7 +20,8 @@ group("common") { } } -use_crashpad_annotation = (is_mac || is_win) && !use_crash_key_stubs +use_crashpad_annotation = + (is_mac || is_win || is_android) && !use_crash_key_stubs buildflag_header("crash_buildflags") { header = "crash_buildflags.h" @@ -143,7 +144,7 @@ source_set("unit_tests") { sources += [ "objc_zombie_unittest.mm" ] } - if (!is_mac && !is_win && !is_fuchsia) { + if (!is_mac && !is_win && !is_fuchsia && !is_android) { include_dirs = [ "//third_party/breakpad/breakpad/src/" ] sources += [ "crash_key_breakpad_unittest.cc" ] } diff --git a/chromium/components/crash/core/common/crash_key.h b/chromium/components/crash/core/common/crash_key.h index c96108a18b3..f27b6eb67f9 100644 --- a/chromium/components/crash/core/common/crash_key.h +++ b/chromium/components/crash/core/common/crash_key.h @@ -217,6 +217,8 @@ CRASH_KEY_EXPORT void InitializeCrashKeys(); #if defined(UNIT_TEST) || defined(CRASH_CORE_COMMON_IMPLEMENTATION) // Returns a value for the crash key named |key_name|. For Crashpad-based // clients, this returns the first instance found of the name. +// Note: In a component build, this will only retrieve crash keys for the +// current component. CRASH_KEY_EXPORT std::string GetCrashKeyValue(const std::string& key_name); // Resets crash key state and, depending on the platform, de-initializes diff --git a/chromium/components/crash/core/common/crash_key_crashpad.cc b/chromium/components/crash/core/common/crash_key_crashpad.cc index 929392e56ec..c6b074897c5 100644 --- a/chromium/components/crash/core/common/crash_key_crashpad.cc +++ b/chromium/components/crash/core/common/crash_key_crashpad.cc @@ -3,7 +3,7 @@ // found in the LICENSE file. // NOTE: This file is only compiled when Crashpad is used as the crash -// reproter. +// reporter. #include "components/crash/core/common/crash_key.h" diff --git a/chromium/components/crash/core/common/crash_key_unittest.cc b/chromium/components/crash/core/common/crash_key_unittest.cc index 466eb25513e..cb9ad9660d6 100644 --- a/chromium/components/crash/core/common/crash_key_unittest.cc +++ b/chromium/components/crash/core/common/crash_key_unittest.cc @@ -6,6 +6,7 @@ #include "base/debug/crash_logging.h" #include "base/debug/stack_trace.h" +#include "base/stl_util.h" #include "build/build_config.h" #include "testing/gtest/include/gtest/gtest.h" @@ -35,7 +36,7 @@ TEST_F(CrashKeyStringTest, FormatStackTrace) { 0x0badbeef, 0x77778888, 0xabc, 0x000ddeeff, 0x12345678, }; base::debug::StackTrace trace(reinterpret_cast<const void* const*>(addresses), - arraysize(addresses)); + base::size(addresses)); std::string too_small = internal::FormatStackTrace(trace, 3); EXPECT_EQ(0u, too_small.size()); @@ -56,7 +57,7 @@ TEST_F(CrashKeyStringTest, FormatStackTrace64) { 0xbaaaabaaaaba, 0x1000000000000000, }; base::debug::StackTrace trace(reinterpret_cast<const void* const*>(addresses), - arraysize(addresses)); + base::size(addresses)); std::string too_small = internal::FormatStackTrace(trace, 8); EXPECT_EQ(0u, too_small.size()); diff --git a/chromium/components/crash/core/common/crash_keys.cc b/chromium/components/crash/core/common/crash_keys.cc index bbb0af7cb05..6a3c9599b3d 100644 --- a/chromium/components/crash/core/common/crash_keys.cc +++ b/chromium/components/crash/core/common/crash_keys.cc @@ -10,6 +10,7 @@ #include "base/command_line.h" #include "base/format_macros.h" #include "base/no_destructor.h" +#include "base/stl_util.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_piece.h" #include "base/strings/string_split.h" @@ -23,7 +24,7 @@ namespace crash_keys { namespace { -#if defined(OS_MACOSX) || defined(OS_WIN) +#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_ANDROID) // When using Crashpad, the crash reporting client ID is the responsibility of // Crashpad. It is not set directly by Chrome. To make the metrics client ID // available on the server, it's stored in a distinct key. @@ -50,7 +51,7 @@ void SetMetricsClientIdFromGUID(const std::string& metrics_client_guid) { } void ClearMetricsClientId() { -#if defined(OS_MACOSX) || defined(OS_WIN) +#if defined(OS_MACOSX) || defined(OS_WIN) || defined(OS_ANDROID) // Crashpad always monitors for crashes, but doesn't upload them when // crash reporting is disabled. The preference to upload crash reports is // linked to the preference for metrics reporting. When metrics reporting is @@ -130,7 +131,7 @@ static PrinterInfoKey printer_info_keys[] = { ScopedPrinterInfo::ScopedPrinterInfo(base::StringPiece data) { std::vector<base::StringPiece> info = base::SplitStringPiece( data, ";", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); - for (size_t i = 0; i < arraysize(printer_info_keys); ++i) { + for (size_t i = 0; i < base::size(printer_info_keys); ++i) { if (i < info.size()) printer_info_keys[i].Set(info[i]); else |