tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 96a3d28b3f9368e5d9333b04ccff020d4fa27d2b
parent 943d62471a99c72daf644b74aef288d729746a3d
Author: Makoto Kato <m_kato@ga2.so-net.ne.jp>
Date:   Tue, 25 Nov 2025 00:35:31 +0000

Bug 2000513 - Clean up duplicated crash reporter launcher. r=geckoview-reviewers,tcampbell

Currently, we have two crash launcher in `GeckoRuntime` and `CrashHandler`,
so this fix merge both with one.

Also, `Context.startForegroundService` might throws
`ForegroundServiceStartNotAllowedException` if Android 12+. So we should
handle it instead of crashing parent process.

Differential Revision: https://phabricator.services.mozilla.com/D272835

Diffstat:
Mmobile/android/geckoview/src/main/java/org/mozilla/geckoview/CrashHandler.java | 126++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mmobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java | 14++++----------
Mmobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/ExampleCrashHandler.java | 7+++++++
3 files changed, 100 insertions(+), 47 deletions(-)

diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/CrashHandler.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/CrashHandler.java @@ -6,12 +6,14 @@ package org.mozilla.geckoview; import android.annotation.SuppressLint; +import android.app.ForegroundServiceStartNotAllowedException; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Process; import android.util.Log; @@ -26,11 +28,14 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.UUID; import org.json.JSONException; import org.json.JSONObject; import org.mozilla.gecko.GeckoAppShell; +import org.mozilla.gecko.util.GeckoBundle; /** Handler for processing application crashes and sending crash reports. */ public class CrashHandler implements Thread.UncaughtExceptionHandler { @@ -351,57 +356,90 @@ public class CrashHandler implements Thread.UncaughtExceptionHandler { @AnyThread public boolean launchCrashReporter( @NonNull final String dumpFile, @NonNull final String extraFile) { - try { - final Context context = getAppContext(); + if (mHandlerService == null) { + Log.w(LOGTAG, "No crash handler service defined, unable to report crash"); + return false; + } - if (mHandlerService == null) { - Log.w(LOGTAG, "No crash handler service defined, unable to report crash"); - return false; - } + return launchCrashReporter( + mHandlerService, + getAppContext(), + getAppPackageName(), + dumpFile, + extraFile, + GeckoRuntime.CRASHED_PROCESS_VISIBILITY_MAIN, + "main", + null); + } + @AnyThread + private static boolean launchCrashReporter( + @NonNull final Class<?> handlerService, + @Nullable final Context context, + @NonNull final String appPackageName, + @NonNull final String dumpFile, + @NonNull final String extraFile, + @NonNull final String visibility, + @NonNull final String processType, + @Nullable final String remoteType) { + try { if (context != null) { - final Intent intent = new Intent(GeckoRuntime.ACTION_CRASHED); + final Intent intent = + new Intent(GeckoRuntime.ACTION_CRASHED, null, context, handlerService); intent.putExtra(GeckoRuntime.EXTRA_MINIDUMP_PATH, dumpFile); intent.putExtra(GeckoRuntime.EXTRA_EXTRAS_PATH, extraFile); - intent.putExtra( - GeckoRuntime.EXTRA_CRASH_PROCESS_VISIBILITY, - GeckoRuntime.CRASHED_PROCESS_VISIBILITY_MAIN); - intent.putExtra(GeckoRuntime.EXTRA_CRASH_PROCESS_TYPE, "main"); - intent.setClass(context, mHandlerService); - + intent.putExtra(GeckoRuntime.EXTRA_CRASH_PROCESS_VISIBILITY, visibility); + intent.putExtra(GeckoRuntime.EXTRA_CRASH_PROCESS_TYPE, processType); + if (remoteType != null) { + intent.putExtra(GeckoRuntime.EXTRA_CRASH_REMOTE_TYPE, remoteType); + } context.startForegroundService(intent); return true; } - final ProcessBuilder pb = - new ProcessBuilder( - "/system/bin/am", - "start-foreground-service", - "--user", - /* USER_CURRENT_OR_SELF */ "-3", - "-a", - GeckoRuntime.ACTION_CRASHED, - "-n", - getAppPackageName() + '/' + mHandlerService.getName(), - "--es", - GeckoRuntime.EXTRA_MINIDUMP_PATH, - dumpFile, - "--es", - GeckoRuntime.EXTRA_EXTRAS_PATH, - extraFile, - "--es", - GeckoRuntime.EXTRA_CRASH_PROCESS_VISIBILITY, - GeckoRuntime.CRASHED_PROCESS_VISIBILITY_MAIN, - "--es", - GeckoRuntime.EXTRA_CRASH_PROCESS_TYPE, - "main"); - - pb.start().waitFor(); + final List<String> args = + new ArrayList<>( + Arrays.asList( + "/system/bin/am", + "start-foreground-service", + "--user", + /* USER_CURRENT_OR_SELF */ "-3", + "-a", + GeckoRuntime.ACTION_CRASHED, + "-n", + appPackageName + '/' + handlerService.getName(), + "--es", + GeckoRuntime.EXTRA_MINIDUMP_PATH, + dumpFile, + "--es", + GeckoRuntime.EXTRA_EXTRAS_PATH, + extraFile, + "--es", + GeckoRuntime.EXTRA_CRASH_PROCESS_VISIBILITY, + visibility, + "--es", + GeckoRuntime.EXTRA_CRASH_PROCESS_TYPE, + processType)); + if (remoteType != null) { + args.add("--es"); + args.add(GeckoRuntime.EXTRA_CRASH_REMOTE_TYPE); + args.add(remoteType); + } + final ProcessBuilder pb = new ProcessBuilder(); + pb.command(args).start().waitFor(); } catch (final IOException e) { Log.e(LOGTAG, "Error launching crash reporter", e); return false; + } catch (final IllegalStateException e) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S + && e instanceof ForegroundServiceStartNotAllowedException) { + Log.e(LOGTAG, "Error launching crash reporter", e); + return false; + } + throw e; + } catch (final InterruptedException e) { Log.i(LOGTAG, "Interrupted while waiting to launch crash reporter", e); // Fall-through @@ -409,6 +447,20 @@ public class CrashHandler implements Thread.UncaughtExceptionHandler { return true; } + @AnyThread + /* package */ static boolean launchCrashReporter( + final Class<?> handlerService, final Context context, final GeckoBundle bundle) { + return launchCrashReporter( + handlerService, + context, + context.getPackageName(), + bundle.getString(GeckoRuntime.EXTRA_MINIDUMP_PATH), + bundle.getString(GeckoRuntime.EXTRA_EXTRAS_PATH), + bundle.getString(GeckoRuntime.EXTRA_CRASH_PROCESS_VISIBILITY), + bundle.getString(GeckoRuntime.EXTRA_CRASH_PROCESS_TYPE), + bundle.getString(GeckoRuntime.EXTRA_CRASH_REMOTE_TYPE)); + } + /** * Report an exception to Socorro. * diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java b/mobile/android/geckoview/src/main/java/org/mozilla/geckoview/GeckoRuntime.java @@ -356,16 +356,10 @@ public final class GeckoRuntime implements Parcelable { return null; }); } else if ("GeckoView:ChildCrashReport".equals(event) && crashHandler != null) { - final Context context = GeckoAppShell.getApplicationContext(); - final Intent i = new Intent(ACTION_CRASHED, null, context, crashHandler); - i.putExtra(EXTRA_MINIDUMP_PATH, message.getString(EXTRA_MINIDUMP_PATH)); - i.putExtra(EXTRA_EXTRAS_PATH, message.getString(EXTRA_EXTRAS_PATH)); - i.putExtra( - EXTRA_CRASH_PROCESS_VISIBILITY, message.getString(EXTRA_CRASH_PROCESS_VISIBILITY)); - i.putExtra(EXTRA_CRASH_PROCESS_TYPE, message.getString(EXTRA_CRASH_PROCESS_TYPE)); - i.putExtra(EXTRA_CRASH_REMOTE_TYPE, message.getString(EXTRA_CRASH_REMOTE_TYPE)); - - context.startForegroundService(i); + CrashHandler.launchCrashReporter( + crashHandler, GeckoAppShell.getApplicationContext(), message); + // TODO(m_kato): + // If returning false, we cannot send crash data, should we re-try it later? } else if ("GeckoView:ServiceWorkerOpenWindow".equals(event)) { final String url = message.getString("url", "about:blank"); serviceWorkerOpenWindow(url) diff --git a/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/ExampleCrashHandler.java b/mobile/android/geckoview_example/src/main/java/org/mozilla/geckoview_example/ExampleCrashHandler.java @@ -49,6 +49,13 @@ public class ExampleCrashHandler extends Service { LOGTAG, "Process Visibility: " + mCrashIntent.getStringExtra(GeckoRuntime.EXTRA_CRASH_PROCESS_VISIBILITY)); + Log.d( + LOGTAG, + "Process Type: " + mCrashIntent.getStringExtra(GeckoRuntime.EXTRA_CRASH_PROCESS_TYPE)); + final String remoteType = mCrashIntent.getStringExtra(GeckoRuntime.EXTRA_CRASH_REMOTE_TYPE); + if (remoteType != null) { + Log.d(LOGTAG, "Remote Type: " + remoteType); + } String id = createNotificationChannel();