Loading cmds/am/src/com/android/commands/am/Am.java +23 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.IPackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; import android.net.Uri; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.RemoteException; Loading Loading @@ -94,6 +95,7 @@ public class Am extends BaseCommand { " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + " am clear-debug-app\n" + " am clear-debug-app\n" + " am monitor [--gdb <port>]\n" + " am monitor [--gdb <port>]\n" + " am hang [--allow-restart]\n" + " am screen-compat [on|off] <PACKAGE>\n" + " am screen-compat [on|off] <PACKAGE>\n" + " am to-uri [INTENT]\n" + " am to-uri [INTENT]\n" + " am to-intent-uri [INTENT]\n" + " am to-intent-uri [INTENT]\n" + Loading Loading @@ -169,6 +171,9 @@ public class Am extends BaseCommand { "am monitor: start monitoring for crashes or ANRs.\n" + "am monitor: start monitoring for crashes or ANRs.\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + "\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" + "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + "\n" + "\n" + "am to-uri: print the given Intent specification as a URI.\n" + "am to-uri: print the given Intent specification as a URI.\n" + Loading Loading @@ -249,6 +254,8 @@ public class Am extends BaseCommand { runBugReport(); runBugReport(); } else if (op.equals("monitor")) { } else if (op.equals("monitor")) { runMonitor(); runMonitor(); } else if (op.equals("hang")) { runHang(); } else if (op.equals("screen-compat")) { } else if (op.equals("screen-compat")) { runScreenCompat(); runScreenCompat(); } else if (op.equals("to-uri")) { } else if (op.equals("to-uri")) { Loading Loading @@ -1304,6 +1311,22 @@ public class Am extends BaseCommand { controller.run(); 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 { private void runScreenCompat() throws Exception { String mode = nextArgRequired(); String mode = nextArgRequired(); boolean enabled; boolean enabled; Loading core/java/android/app/ActivityManagerNative.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -1870,6 +1870,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; 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); return super.onTransact(code, data, reply, flags); Loading Loading @@ -4270,5 +4279,17 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); 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; private IBinder mRemote; } } core/java/android/app/IActivityManager.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -377,6 +377,8 @@ public interface IActivityManager extends IInterface { public void killUid(int uid, String reason) throws RemoteException; public void killUid(int uid, String reason) throws RemoteException; public void hang(IBinder who, boolean allowRestart) throws RemoteException; /* /* * Private non-Binder interfaces * Private non-Binder interfaces */ */ Loading Loading @@ -638,4 +640,5 @@ public interface IActivityManager extends IInterface { int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163; int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163; int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164; int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164; int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165; int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165; int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166; } } services/java/com/android/server/Watchdog.java +14 −3 Original line number Original line Diff line number Diff line Loading @@ -95,6 +95,7 @@ public class Watchdog extends Thread { int mPhonePid; int mPhonePid; IActivityController mController; IActivityController mController; boolean mAllowRestart = true; final Calendar mCalendar = Calendar.getInstance(); final Calendar mCalendar = Calendar.getInstance(); int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; Loading Loading @@ -233,6 +234,12 @@ public class Watchdog extends Thread { } } } } public void setAllowRestart(boolean allowRestart) { synchronized (this) { mAllowRestart = allowRestart; } } public void addMonitor(Monitor monitor) { public void addMonitor(Monitor monitor) { synchronized (this) { synchronized (this) { if (isAlive()) { if (isAlive()) { Loading Loading @@ -401,6 +408,7 @@ public class Watchdog extends Thread { final String name; final String name; final boolean allowRestart; synchronized (this) { synchronized (this) { long timeout = TIME_TO_WAIT; long timeout = TIME_TO_WAIT; Loading Loading @@ -437,6 +445,7 @@ public class Watchdog extends Thread { name = (mCurrentMonitor != null) ? name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null"; mCurrentMonitor.getClass().getName() : "null"; allowRestart = mAllowRestart; } } // If we got here, that means that the system is most likely hung. // If we got here, that means that the system is most likely hung. Loading Loading @@ -506,12 +515,14 @@ public class Watchdog extends Thread { } } // Only kill the process if the debugger is not attached. // 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); Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name); Process.killProcess(Process.myPid()); Process.killProcess(Process.myPid()); System.exit(10); System.exit(10); } else { Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process"); } } waitedHalf = false; waitedHalf = false; Loading services/java/com/android/server/am/ActivityManagerService.java +39 −0 Original line number Original line Diff line number Diff line Loading @@ -7813,6 +7813,45 @@ public final class ActivityManagerService extends ActivityManagerNative return killed; 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, public final void startRunning(String pkg, String cls, String action, String data) { String data) { synchronized(this) { synchronized(this) { Loading Loading
cmds/am/src/com/android/commands/am/Am.java +23 −0 Original line number Original line Diff line number Diff line Loading @@ -31,6 +31,7 @@ import android.content.Intent; import android.content.pm.IPackageManager; import android.content.pm.IPackageManager; import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo; import android.net.Uri; import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.RemoteException; Loading Loading @@ -94,6 +95,7 @@ public class Am extends BaseCommand { " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + " am set-debug-app [-w] [--persistent] <PACKAGE>\n" + " am clear-debug-app\n" + " am clear-debug-app\n" + " am monitor [--gdb <port>]\n" + " am monitor [--gdb <port>]\n" + " am hang [--allow-restart]\n" + " am screen-compat [on|off] <PACKAGE>\n" + " am screen-compat [on|off] <PACKAGE>\n" + " am to-uri [INTENT]\n" + " am to-uri [INTENT]\n" + " am to-intent-uri [INTENT]\n" + " am to-intent-uri [INTENT]\n" + Loading Loading @@ -169,6 +171,9 @@ public class Am extends BaseCommand { "am monitor: start monitoring for crashes or ANRs.\n" + "am monitor: start monitoring for crashes or ANRs.\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + " --gdb: start gdbserv on the given port at crash/ANR\n" + "\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" + "am screen-compat: control screen compatibility mode of <PACKAGE>.\n" + "\n" + "\n" + "am to-uri: print the given Intent specification as a URI.\n" + "am to-uri: print the given Intent specification as a URI.\n" + Loading Loading @@ -249,6 +254,8 @@ public class Am extends BaseCommand { runBugReport(); runBugReport(); } else if (op.equals("monitor")) { } else if (op.equals("monitor")) { runMonitor(); runMonitor(); } else if (op.equals("hang")) { runHang(); } else if (op.equals("screen-compat")) { } else if (op.equals("screen-compat")) { runScreenCompat(); runScreenCompat(); } else if (op.equals("to-uri")) { } else if (op.equals("to-uri")) { Loading Loading @@ -1304,6 +1311,22 @@ public class Am extends BaseCommand { controller.run(); 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 { private void runScreenCompat() throws Exception { String mode = nextArgRequired(); String mode = nextArgRequired(); boolean enabled; boolean enabled; Loading
core/java/android/app/ActivityManagerNative.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -1870,6 +1870,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; 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); return super.onTransact(code, data, reply, flags); Loading Loading @@ -4270,5 +4279,17 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); 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; private IBinder mRemote; } }
core/java/android/app/IActivityManager.java +3 −0 Original line number Original line Diff line number Diff line Loading @@ -377,6 +377,8 @@ public interface IActivityManager extends IInterface { public void killUid(int uid, String reason) throws RemoteException; public void killUid(int uid, String reason) throws RemoteException; public void hang(IBinder who, boolean allowRestart) throws RemoteException; /* /* * Private non-Binder interfaces * Private non-Binder interfaces */ */ Loading Loading @@ -638,4 +640,5 @@ public interface IActivityManager extends IInterface { int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163; int GET_LAUNCHED_FROM_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+163; int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164; int KILL_UID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+164; int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165; int SET_USER_IS_MONKEY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+165; int HANG_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+166; } }
services/java/com/android/server/Watchdog.java +14 −3 Original line number Original line Diff line number Diff line Loading @@ -95,6 +95,7 @@ public class Watchdog extends Thread { int mPhonePid; int mPhonePid; IActivityController mController; IActivityController mController; boolean mAllowRestart = true; final Calendar mCalendar = Calendar.getInstance(); final Calendar mCalendar = Calendar.getInstance(); int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF; Loading Loading @@ -233,6 +234,12 @@ public class Watchdog extends Thread { } } } } public void setAllowRestart(boolean allowRestart) { synchronized (this) { mAllowRestart = allowRestart; } } public void addMonitor(Monitor monitor) { public void addMonitor(Monitor monitor) { synchronized (this) { synchronized (this) { if (isAlive()) { if (isAlive()) { Loading Loading @@ -401,6 +408,7 @@ public class Watchdog extends Thread { final String name; final String name; final boolean allowRestart; synchronized (this) { synchronized (this) { long timeout = TIME_TO_WAIT; long timeout = TIME_TO_WAIT; Loading Loading @@ -437,6 +445,7 @@ public class Watchdog extends Thread { name = (mCurrentMonitor != null) ? name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null"; mCurrentMonitor.getClass().getName() : "null"; allowRestart = mAllowRestart; } } // If we got here, that means that the system is most likely hung. // If we got here, that means that the system is most likely hung. Loading Loading @@ -506,12 +515,14 @@ public class Watchdog extends Thread { } } // Only kill the process if the debugger is not attached. // 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); Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name); Process.killProcess(Process.myPid()); Process.killProcess(Process.myPid()); System.exit(10); System.exit(10); } else { Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process"); } } waitedHalf = false; waitedHalf = false; Loading
services/java/com/android/server/am/ActivityManagerService.java +39 −0 Original line number Original line Diff line number Diff line Loading @@ -7813,6 +7813,45 @@ public final class ActivityManagerService extends ActivityManagerNative return killed; 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, public final void startRunning(String pkg, String cls, String action, String data) { String data) { synchronized(this) { synchronized(this) { Loading