Ignore first crash dialog.

By default, no longer show the crash dialog the first time an app
crashes. Instead, only multiple crashes will show by default.

Add Settings.Global and Settings.Secure flags to toggle this behavior.
Settings.Secure value is controlled via a setting in developer options.

Ensure Settings.Secure is backed up but Global value is not.

Bug: 63703353, 70640329
Test: SettingsBackupTest, manual crashing with a test app

Change-Id: Ib0a66cabdf60aad5e60eded9bfb96e3126bf032f
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 24e56c0..396c897 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6562,6 +6562,14 @@
         public static final String ANR_SHOW_BACKGROUND = "anr_show_background";
 
         /**
+         * If nonzero, crashes in foreground processes will bring up a dialog.
+         * Otherwise, the process will be silently killed.
+         * @hide
+         */
+        public static final String SHOW_FIRST_CRASH_DIALOG_DEV_OPTION =
+                "show_first_crash_dialog_dev_option";
+
+        /**
          * The {@link ComponentName} string of the service to be used as the voice recognition
          * service.
          *
@@ -7398,6 +7406,7 @@
             SCREENSAVER_ACTIVATE_ON_DOCK,
             SCREENSAVER_ACTIVATE_ON_SLEEP,
             LOCKDOWN_IN_POWER_MENU,
+            SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
         };
 
         /** @hide */
@@ -11316,6 +11325,13 @@
          */
         public static final String ENABLE_SMART_REPLIES_IN_NOTIFICATIONS =
                 "enable_smart_replies_in_notifications";
+
+        /**
+         * If nonzero, crashes in foreground processes will bring up a dialog.
+         * Otherwise, the process will be silently killed.
+         * @hide
+         */
+        public static final String SHOW_FIRST_CRASH_DIALOG = "show_first_crash_dialog";
     }
 
     /**
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index 3ffb254..8d6df12 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -390,8 +390,9 @@
     optional SettingProto enable_gnss_raw_meas_full_tracking = 346;
     optional SettingProto zram_enabled = 347;
     optional SettingProto enable_smart_replies_in_notifications = 348;
+    optional SettingProto show_first_crash_dialog = 349;
 
-    // Next tag = 349;
+    // Next tag = 350;
 }
 
 message SecureSettingsProto {
@@ -593,8 +594,9 @@
     optional SettingProto qs_auto_added_tiles = 193;
     optional SettingProto lockdown_in_power_menu = 194;
     optional SettingProto backup_manager_constants = 169;
+    optional SettingProto show_first_crash_dialog_dev_option = 195;
 
-    // Next tag = 195
+    // Next tag = 196
 }
 
 message SystemSettingsProto {
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index d5689c7..c2ae776 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -331,6 +331,7 @@
                     Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
                     Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
                     Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+                    Settings.Global.SHOW_FIRST_CRASH_DIALOG,
                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
                     Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index d33e084..87ed7eb 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1125,6 +1125,9 @@
         dumpSetting(s, p,
                 Settings.Global.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS,
                 GlobalSettingsProto.ENABLE_SMART_REPLIES_IN_NOTIFICATIONS);
+        dumpSetting(s, p,
+                Settings.Global.SHOW_FIRST_CRASH_DIALOG,
+                GlobalSettingsProto.SHOW_FIRST_CRASH_DIALOG);
     }
 
     /** Dump a single {@link SettingsState.Setting} to a proto buf */
@@ -1516,6 +1519,9 @@
                 Settings.Secure.ANR_SHOW_BACKGROUND,
                 SecureSettingsProto.ANR_SHOW_BACKGROUND);
         dumpSetting(s, p,
+                Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+                SecureSettingsProto.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION);
+        dumpSetting(s, p,
                 Settings.Secure.VOICE_RECOGNITION_SERVICE,
                 SecureSettingsProto.VOICE_RECOGNITION_SERVICE);
         dumpSetting(s, p,
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 35465a7..8910274 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -738,9 +738,18 @@
                 }
                 return;
             }
+            final boolean showFirstCrash = Settings.Global.getInt(
+                    mContext.getContentResolver(),
+                    Settings.Global.SHOW_FIRST_CRASH_DIALOG, 0) != 0;
+            final boolean showFirstCrashDevOption = Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.SHOW_FIRST_CRASH_DIALOG_DEV_OPTION,
+                    0,
+                    UserHandle.USER_CURRENT) != 0;
             final boolean crashSilenced = mAppsNotReportingCrashes != null &&
                     mAppsNotReportingCrashes.contains(proc.info.packageName);
-            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced) {
+            if ((mService.canShowErrorDialogs() || showBackground) && !crashSilenced
+                    && (showFirstCrash || showFirstCrashDevOption || data.repeating)) {
                 proc.crashDialog = new AppErrorDialog(mContext, mService, data);
             } else {
                 // The device is asleep, so just pretend that the user