If a crash dialog can't be shown, just kill the process.

scheduleCrash() calls into the app process to ask it to nicely show
the crash dialog. If that call fails, rather than just silently
stopping, kill the process right away. It might be out of control.

This also adds an additional check for killedByAm to the flow there
so if the activity manager already has killed it, the dialog won't
be shown.

Bug: 28196243
Change-Id: I979f01074e5890640e7b06e29eeb0d6c38803569
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 93d4060..059acbd 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -37,9 +37,11 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.CompatibilityInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -552,6 +554,29 @@
         return adj;
     }
 
+    void scheduleCrash(String message) {
+        // Checking killedbyAm should keep it from showing the crash dialog if the process
+        // was already dead for a good / normal reason.
+        if (!killedByAm) {
+            if (thread != null) {
+                if (pid == Process.myPid()) {
+                    Slog.w(TAG, "scheduleCrash: trying to crash system process!");
+                    return;
+                }
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    thread.scheduleCrash(message);
+                } catch (RemoteException e) {
+                    // If it's already dead our work is done. If it's wedged just kill it.
+                    // We won't get the crash dialog or the error reporting.
+                    kill("scheduleCrash for '" + message + "' failed", true);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+
     void kill(String reason, boolean noisy) {
         if (!killedByAm) {
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");