diff options
| author | 2017-01-20 17:50:32 -0800 | |
|---|---|---|
| committer | 2017-01-23 20:18:45 +0000 | |
| commit | 8aa8fe128992f7e47ecbc8588027eaec82012f3a (patch) | |
| tree | 32221d72da4d9457b220f3abc69e4c7842de1b5d | |
| parent | 4a65687b853a92268f4f0eb52f22e092b16f8ed3 (diff) | |
Add an 'am crash' shell command
Induce a normal VM crash via adb, because it's quite different from the
effects of 'am kill'.
Test: induced crashes via adb shell using both pid & pkg
Change-Id: I79654afa7c4a70364cfd7d3af3e80a7b0e59b882
6 files changed, 50 insertions, 9 deletions
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 135c2a4eef91..41e850c2ede4 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -264,7 +264,7 @@ interface IActivityManager { boolean isImmersive(in IBinder token); void setImmersive(in IBinder token, boolean immersive); boolean isTopActivityImmersive(); - void crashApplication(int uid, int initialPid, in String packageName, in String message); + void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message); String getProviderMimeType(in Uri uri, int userId); IBinder newUriPermissionOwner(in String name); void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg, diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8a0baad3268d..3dcc0fe51020 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -4936,7 +4936,7 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void crashApplication(int uid, int initialPid, String packageName, + public void crashApplication(int uid, int initialPid, String packageName, int userId, String message) { if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES) != PackageManager.PERMISSION_GRANTED) { @@ -4949,7 +4949,7 @@ public class ActivityManagerService extends IActivityManager.Stub } synchronized(this) { - mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, message); + mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message); } } diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 202868a3da42..1a2a31b5885c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -167,6 +167,8 @@ final class ActivityManagerShellCommand extends ShellCommand { return runBugReport(pw); case "force-stop": return runForceStop(pw); + case "crash": + return runCrash(pw); case "kill": return runKill(pw); case "kill-all": @@ -851,6 +853,32 @@ final class ActivityManagerShellCommand extends ShellCommand { return 0; } + int runCrash(PrintWriter pw) throws RemoteException { + int userId = UserHandle.USER_ALL; + + String opt; + while ((opt=getNextOption()) != null) { + if (opt.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else { + getErrPrintWriter().println("Error: Unknown option: " + opt); + return -1; + } + } + + int pid = -1; + String packageName = null; + final String arg = getNextArgRequired(); + // The argument is either a pid or a package name + try { + pid = Integer.parseInt(arg); + } catch (NumberFormatException e) { + packageName = arg; + } + mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash"); + return 0; + } + int runKill(PrintWriter pw) throws RemoteException { int userId = UserHandle.USER_ALL; @@ -2480,6 +2508,8 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" --telephony: will dump only telephony sections."); pw.println(" force-stop [--user <USER_ID> | all | current] <PACKAGE>"); pw.println(" Completely stop the given application package."); + pw.println(" crash [--user <USER_ID>] <PACKAGE|PID>"); + pw.println(" Induce a VM crash in the specified package or process"); pw.println(" kill [--user <USER_ID> | all | current] <PACKAGE>"); pw.println(" Kill all processes associated with the given application."); pw.println(" kill-all"); diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java index 739a8c464556..384f2f8662b8 100644 --- a/services/core/java/com/android/server/am/AppErrors.java +++ b/services/core/java/com/android/server/am/AppErrors.java @@ -259,7 +259,16 @@ class AppErrors { } } - void scheduleAppCrashLocked(int uid, int initialPid, String packageName, + /** + * Induce a crash in the given app. + * + * @param uid if nonnegative, the required matching uid of the target to crash + * @param initialPid fast-path match for the target to crash + * @param packageName fallback match if the stated pid is not found or doesn't match uid + * @param userId If nonnegative, required to identify a match by package name + * @param message + */ + void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId, String message) { ProcessRecord proc = null; @@ -270,14 +279,15 @@ class AppErrors { synchronized (mService.mPidsSelfLocked) { for (int i=0; i<mService.mPidsSelfLocked.size(); i++) { ProcessRecord p = mService.mPidsSelfLocked.valueAt(i); - if (p.uid != uid) { + if (uid >= 0 && p.uid != uid) { continue; } if (p.pid == initialPid) { proc = p; break; } - if (p.pkgList.containsKey(packageName)) { + if (p.pkgList.containsKey(packageName) + && (userId < 0 || p.userId == userId)) { proc = p; } } @@ -286,7 +296,8 @@ class AppErrors { if (proc == null) { Slog.w(TAG, "crashApplication: nothing for uid=" + uid + " initialPid=" + initialPid - + " packageName=" + packageName); + + " packageName=" + packageName + + " userId=" + userId); return; } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 71c7fd348fb3..82b00da5b809 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -534,7 +534,7 @@ final class ServiceRecord extends Binder { // get to be foreground. ams.setServiceForeground(name, ServiceRecord.this, 0, null, 0); - ams.crashApplication(appUid, appPid, localPackageName, + ams.crashApplication(appUid, appPid, localPackageName, -1, "Bad notification for startForeground: " + e); } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 323b468d9b48..168884dbe189 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -605,7 +605,7 @@ public class NotificationManagerService extends SystemService { REASON_DELEGATE_ERROR, null); long ident = Binder.clearCallingIdentity(); try { - ActivityManager.getService().crashApplication(uid, initialPid, pkg, + ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1, "Bad notification posted from package " + pkg + ": " + message); } catch (RemoteException e) { |