summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2013-05-06 16:07:26 -0700
committerDianne Hackborn <hackbod@google.com>2013-05-06 16:07:26 -0700
commit8bd64df2adb26fe9547ae3961a58631e241b613e (patch)
tree060a9ddad01b6dfd4f24abdd323a9b0873b32982
parent5b88a2fd7b77880f6e09ae4a1de509bebe28bc3a (diff)
downloadframeworks_base-8bd64df2adb26fe9547ae3961a58631e241b613e.zip
frameworks_base-8bd64df2adb26fe9547ae3961a58631e241b613e.tar.gz
frameworks_base-8bd64df2adb26fe9547ae3961a58631e241b613e.tar.bz2
Help for the debugging help for issue #8734824.
Add a new "hang" am command that lets you hang the system process. Useful for testing. Change-Id: Ice0fc52b49d80e5189f016108b03f9fd549b58a7
-rw-r--r--cmds/am/src/com/android/commands/am/Am.java23
-rw-r--r--core/java/android/app/ActivityManagerNative.java21
-rw-r--r--core/java/android/app/IActivityManager.java3
-rw-r--r--services/java/com/android/server/Watchdog.java17
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java39
5 files changed, 100 insertions, 3 deletions
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 93658e1..61fe340 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -31,6 +31,7 @@ import android.content.Intent;
import android.content.pm.IPackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
@@ -94,6 +95,7 @@ public class Am extends BaseCommand {
" am set-debug-app [-w] [--persistent] <PACKAGE>\n" +
" am clear-debug-app\n" +
" am monitor [--gdb <port>]\n" +
+ " am hang [--allow-restart]\n" +
" am screen-compat [on|off] <PACKAGE>\n" +
" am to-uri [INTENT]\n" +
" am to-intent-uri [INTENT]\n" +
@@ -169,6 +171,9 @@ public class Am extends BaseCommand {
"am monitor: start monitoring for crashes or ANRs.\n" +
" --gdb: start gdbserv on the given port at crash/ANR\n" +
"\n" +
+ "am hang: hang the system.\n" +
+ " --allow-restart: allow watchdog to perform normal system restart\n" +
+ "\n" +
"am screen-compat: control screen compatibility mode of <PACKAGE>.\n" +
"\n" +
"am to-uri: print the given Intent specification as a URI.\n" +
@@ -249,6 +254,8 @@ public class Am extends BaseCommand {
runBugReport();
} else if (op.equals("monitor")) {
runMonitor();
+ } else if (op.equals("hang")) {
+ runHang();
} else if (op.equals("screen-compat")) {
runScreenCompat();
} else if (op.equals("to-uri")) {
@@ -1304,6 +1311,22 @@ public class Am extends BaseCommand {
controller.run();
}
+ private void runHang() throws Exception {
+ String opt;
+ boolean allowRestart = false;
+ while ((opt=nextOption()) != null) {
+ if (opt.equals("--allow-restart")) {
+ allowRestart = true;
+ } else {
+ System.err.println("Error: Unknown option: " + opt);
+ return;
+ }
+ }
+
+ System.out.println("Hanging the system...");
+ mAm.hang(new Binder(), allowRestart);
+ }
+
private void runScreenCompat() throws Exception {
String mode = nextArgRequired();
boolean enabled;
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 98baa0e..d4478bf 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1870,6 +1870,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case HANG_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ IBinder who = data.readStrongBinder();
+ boolean allowRestart = data.readInt() != 0;
+ hang(who, allowRestart);
+ reply.writeNoException();
+ return true;
+ }
+
}
return super.onTransact(code, data, reply, flags);
@@ -4270,5 +4279,17 @@ class ActivityManagerProxy implements IActivityManager
reply.recycle();
}
+ public void hang(IBinder who, boolean allowRestart) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ data.writeStrongBinder(who);
+ data.writeInt(allowRestart ? 1 : 0);
+ mRemote.transact(HANG_TRANSACTION, data, reply, 0);
+ reply.readException();
+ data.recycle();
+ reply.recycle();
+ }
+
private IBinder mRemote;
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 33a2770..a21caee 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -377,6 +377,8 @@ public interface IActivityManager extends IInterface {
public void killUid(int uid, String reason) throws RemoteException;
+ public void hang(IBinder who, boolean allowRestart) throws RemoteException;
+
/*
* Private non-Binder interfaces
*/
@@ -638,4 +640,5 @@ public interface IActivityManager extends IInterface {
int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163;
int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164;
int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165;
+ int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166;
}
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index e784cf2..3aec4ea 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -95,6 +95,7 @@ public class Watchdog extends Thread {
int mPhonePid;
IActivityController mController;
+ boolean mAllowRestart = true;
final Calendar mCalendar = Calendar.getInstance();
int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
@@ -233,6 +234,12 @@ public class Watchdog extends Thread {
}
}
+ public void setAllowRestart(boolean allowRestart) {
+ synchronized (this) {
+ mAllowRestart = allowRestart;
+ }
+ }
+
public void addMonitor(Monitor monitor) {
synchronized (this) {
if (isAlive()) {
@@ -401,6 +408,7 @@ public class Watchdog extends Thread {
final String name;
+ final boolean allowRestart;
synchronized (this) {
long timeout = TIME_TO_WAIT;
@@ -437,6 +445,7 @@ public class Watchdog extends Thread {
name = (mCurrentMonitor != null) ?
mCurrentMonitor.getClass().getName() : "null";
+ allowRestart = mAllowRestart;
}
// If we got here, that means that the system is most likely hung.
@@ -506,12 +515,14 @@ public class Watchdog extends Thread {
}
// Only kill the process if the debugger is not attached.
- if (!Debug.isDebuggerConnected()) {
+ if (Debug.isDebuggerConnected()) {
+ Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
+ } else if (!allowRestart) {
+ Slog.w(TAG, "Restart not allowed: Watchdog is *not* killing the system process");
+ } else {
Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);
Process.killProcess(Process.myPid());
System.exit(10);
- } else {
- Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
}
waitedHalf = false;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index cbeed7b..0081dfc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7813,6 +7813,45 @@ public final class ActivityManagerService extends ActivityManagerNative
return killed;
}
+ @Override
+ public void hang(final IBinder who, boolean allowRestart) {
+ if (checkCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Requires permission "
+ + android.Manifest.permission.SET_ACTIVITY_WATCHER);
+ }
+
+ final IBinder.DeathRecipient death = new DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+ };
+
+ try {
+ who.linkToDeath(death, 0);
+ } catch (RemoteException e) {
+ Slog.w(TAG, "hang: given caller IBinder is already dead.");
+ return;
+ }
+
+ synchronized (this) {
+ Watchdog.getInstance().setAllowRestart(allowRestart);
+ Slog.i(TAG, "Hanging system process at request of pid " + Binder.getCallingPid());
+ synchronized (death) {
+ while (who.isBinderAlive()) {
+ try {
+ death.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ Watchdog.getInstance().setAllowRestart(true);
+ }
+ }
+
public final void startRunning(String pkg, String cls, String action,
String data) {
synchronized(this) {