Merge "New ActivityManager<->debuggerd protocol for recoverable crashes." am: f62a0533d7
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/2485756 Change-Id: I801f963f099af5c780bc927b0292355a9020f874 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -8415,13 +8415,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean recoverable = eventType.equals("native_recoverable_crash");
|
||||||
|
|
||||||
EventLogTags.writeAmCrash(Binder.getCallingPid(),
|
EventLogTags.writeAmCrash(Binder.getCallingPid(),
|
||||||
UserHandle.getUserId(Binder.getCallingUid()), processName,
|
UserHandle.getUserId(Binder.getCallingUid()), processName,
|
||||||
r == null ? -1 : r.info.flags,
|
r == null ? -1 : r.info.flags,
|
||||||
crashInfo.exceptionClassName,
|
crashInfo.exceptionClassName,
|
||||||
crashInfo.exceptionMessage,
|
crashInfo.exceptionMessage,
|
||||||
crashInfo.throwFileName,
|
crashInfo.throwFileName,
|
||||||
crashInfo.throwLineNumber);
|
crashInfo.throwLineNumber,
|
||||||
|
recoverable ? 1 : 0);
|
||||||
|
|
||||||
int processClassEnum = processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER
|
int processClassEnum = processName.equals("system_server") ? ServerProtoEnums.SYSTEM_SERVER
|
||||||
: (r != null) ? r.getProcessClassEnum()
|
: (r != null) ? r.getProcessClassEnum()
|
||||||
@@ -8489,8 +8492,14 @@ public class ActivityManagerService extends IActivityManager.Stub
|
|||||||
eventType, r, processName, null, null, null, null, null, null, crashInfo,
|
eventType, r, processName, null, null, null, null, null, null, crashInfo,
|
||||||
new Float(loadingProgress), incrementalMetrics, null);
|
new Float(loadingProgress), incrementalMetrics, null);
|
||||||
|
|
||||||
|
// For GWP-ASan recoverable crashes, don't make the app crash (the whole point of
|
||||||
|
// 'recoverable' is that the app doesn't crash). Normally, for nonrecoreable native crashes,
|
||||||
|
// debuggerd will terminate the process, but there's a backup where ActivityManager will
|
||||||
|
// also kill it. Avoid that.
|
||||||
|
if (!recoverable) {
|
||||||
mAppErrors.crashApplication(r, crashInfo);
|
mAppErrors.crashApplication(r, crashInfo);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void handleApplicationStrictModeViolation(
|
public void handleApplicationStrictModeViolation(
|
||||||
IBinder app,
|
IBinder app,
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ option java_package com.android.server.am
|
|||||||
30037 am_process_start_timeout (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3)
|
30037 am_process_start_timeout (User|1|5),(PID|1|5),(UID|1|5),(Process Name|3)
|
||||||
|
|
||||||
# Unhandled exception
|
# Unhandled exception
|
||||||
30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5)
|
30039 am_crash (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Exception|3),(Message|3),(File|3),(Line|1|5),(Recoverable|1|5)
|
||||||
# Log.wtf() called
|
# Log.wtf() called
|
||||||
30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3)
|
30040 am_wtf (User|1|5),(PID|1|5),(Process Name|3),(Flags|1|5),(Tag|3),(Message|3)
|
||||||
|
|
||||||
|
|||||||
@@ -64,12 +64,15 @@ final class NativeCrashListener extends Thread {
|
|||||||
class NativeCrashReporter extends Thread {
|
class NativeCrashReporter extends Thread {
|
||||||
ProcessRecord mApp;
|
ProcessRecord mApp;
|
||||||
int mSignal;
|
int mSignal;
|
||||||
|
boolean mGwpAsanRecoverableCrash;
|
||||||
String mCrashReport;
|
String mCrashReport;
|
||||||
|
|
||||||
NativeCrashReporter(ProcessRecord app, int signal, String report) {
|
NativeCrashReporter(ProcessRecord app, int signal, boolean gwpAsanRecoverableCrash,
|
||||||
|
String report) {
|
||||||
super("NativeCrashReport");
|
super("NativeCrashReport");
|
||||||
mApp = app;
|
mApp = app;
|
||||||
mSignal = signal;
|
mSignal = signal;
|
||||||
|
mGwpAsanRecoverableCrash = gwpAsanRecoverableCrash;
|
||||||
mCrashReport = report;
|
mCrashReport = report;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +88,9 @@ final class NativeCrashListener extends Thread {
|
|||||||
ci.stackTrace = mCrashReport;
|
ci.stackTrace = mCrashReport;
|
||||||
|
|
||||||
if (DEBUG) Slog.v(TAG, "Calling handleApplicationCrash()");
|
if (DEBUG) Slog.v(TAG, "Calling handleApplicationCrash()");
|
||||||
mAm.handleApplicationCrashInner("native_crash", mApp, mApp.processName, ci);
|
mAm.handleApplicationCrashInner(
|
||||||
|
mGwpAsanRecoverableCrash ? "native_recoverable_crash" : "native_crash",
|
||||||
|
mApp, mApp.processName, ci);
|
||||||
if (DEBUG) Slog.v(TAG, "<-- handleApplicationCrash() returned");
|
if (DEBUG) Slog.v(TAG, "<-- handleApplicationCrash() returned");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Slog.e(TAG, "Unable to report native crash", e);
|
Slog.e(TAG, "Unable to report native crash", e);
|
||||||
@@ -207,9 +212,14 @@ final class NativeCrashListener extends Thread {
|
|||||||
// permits crash_dump to connect to it. This allows us to trust the
|
// permits crash_dump to connect to it. This allows us to trust the
|
||||||
// received values.
|
// received values.
|
||||||
|
|
||||||
// first, the pid and signal number
|
// Activity Manager protocol:
|
||||||
int headerBytes = readExactly(fd, buf, 0, 8);
|
// - 32-bit network-byte-order: pid
|
||||||
if (headerBytes != 8) {
|
// - 32-bit network-byte-order: signal number
|
||||||
|
// - byte: gwpAsanRecoverableCrash
|
||||||
|
// - bytes: raw text of the dump
|
||||||
|
// - null terminator
|
||||||
|
int headerBytes = readExactly(fd, buf, 0, 9);
|
||||||
|
if (headerBytes != 9) {
|
||||||
// protocol failure; give up
|
// protocol failure; give up
|
||||||
Slog.e(TAG, "Unable to read from debuggerd");
|
Slog.e(TAG, "Unable to read from debuggerd");
|
||||||
return;
|
return;
|
||||||
@@ -217,17 +227,26 @@ final class NativeCrashListener extends Thread {
|
|||||||
|
|
||||||
int pid = unpackInt(buf, 0);
|
int pid = unpackInt(buf, 0);
|
||||||
int signal = unpackInt(buf, 4);
|
int signal = unpackInt(buf, 4);
|
||||||
|
boolean gwpAsanRecoverableCrash = buf[8] != 0;
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Slog.v(TAG, "Read pid=" + pid + " signal=" + signal);
|
Slog.v(TAG, "Read pid=" + pid + " signal=" + signal
|
||||||
|
+ " recoverable=" + gwpAsanRecoverableCrash);
|
||||||
|
}
|
||||||
|
if (pid < 0) {
|
||||||
|
Slog.e(TAG, "Bogus pid!");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now the text of the dump
|
// now the text of the dump
|
||||||
if (pid > 0) {
|
|
||||||
final ProcessRecord pr;
|
final ProcessRecord pr;
|
||||||
synchronized (mAm.mPidsSelfLocked) {
|
synchronized (mAm.mPidsSelfLocked) {
|
||||||
pr = mAm.mPidsSelfLocked.get(pid);
|
pr = mAm.mPidsSelfLocked.get(pid);
|
||||||
}
|
}
|
||||||
if (pr != null) {
|
if (pr == null) {
|
||||||
|
Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Don't attempt crash reporting for persistent apps
|
// Don't attempt crash reporting for persistent apps
|
||||||
if (pr.isPersistent()) {
|
if (pr.isPersistent()) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@@ -259,27 +278,25 @@ final class NativeCrashListener extends Thread {
|
|||||||
if (DEBUG) Slog.v(TAG, "processing");
|
if (DEBUG) Slog.v(TAG, "processing");
|
||||||
|
|
||||||
// Mark the process record as being a native crash so that the
|
// Mark the process record as being a native crash so that the
|
||||||
// cleanup mechanism knows we're still submitting the report
|
// cleanup mechanism knows we're still submitting the report even
|
||||||
// even though the process will vanish as soon as we let
|
// though the process will vanish as soon as we let debuggerd
|
||||||
// debuggerd proceed.
|
// proceed. This isn't relevant for recoverable crashes, as we don't
|
||||||
|
// show the user an "app crashed" dialogue because the app (by
|
||||||
|
// design) didn't crash.
|
||||||
|
if (!gwpAsanRecoverableCrash) {
|
||||||
synchronized (mAm) {
|
synchronized (mAm) {
|
||||||
synchronized (mAm.mProcLock) {
|
synchronized (mAm.mProcLock) {
|
||||||
pr.mErrorState.setCrashing(true);
|
pr.mErrorState.setCrashing(true);
|
||||||
pr.mErrorState.setForceCrashReport(true);
|
pr.mErrorState.setForceCrashReport(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Crash reporting is synchronous but we want to let debuggerd
|
// Crash reporting is synchronous but we want to let debuggerd
|
||||||
// go about it business right away, so we spin off the actual
|
// go about it business right away, so we spin off the actual
|
||||||
// reporting logic on a thread and let it take it's time.
|
// reporting logic on a thread and let it take it's time.
|
||||||
final String reportString = new String(os.toByteArray(), "UTF-8");
|
final String reportString = new String(os.toByteArray(), "UTF-8");
|
||||||
(new NativeCrashReporter(pr, signal, reportString)).start();
|
(new NativeCrashReporter(pr, signal, gwpAsanRecoverableCrash, reportString)).start();
|
||||||
} else {
|
|
||||||
Slog.w(TAG, "Couldn't find ProcessRecord for pid " + pid);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Slog.e(TAG, "Bogus pid!");
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Slog.e(TAG, "Exception dealing with report", e);
|
Slog.e(TAG, "Exception dealing with report", e);
|
||||||
// ugh, fail.
|
// ugh, fail.
|
||||||
|
|||||||
Reference in New Issue
Block a user