diff options
| author | 2012-10-04 11:58:16 -0700 | |
|---|---|---|
| committer | 2012-10-04 12:04:58 -0700 | |
| commit | 5fe7e2a3043d6a8ca933c77ccf95c791b57b221a (patch) | |
| tree | f45af64c05358cec85257742b108b775c5cee8b3 | |
| parent | f7ee2a03c1f930db4b20c04225f496ada97e646b (diff) | |
Fix issue #6968859: home not exiting an ANR'd dream
Add a new call to the activity manager for the input dispatcher
to report about any pid having an ANR. This has a new feature
where it can also tell the activity manager that it is above the
system alert layer, so the activity manager can pop its ANR dialog
on top of everything if it needs to. (Normally we don't want
these dialogs appearing on top of the lock screen.)
Also fixed some debugging stuff here and there that was useful
as I was working on this -- windows now very clearly include
their uid, various system dialogs now have titles so you know
what they are in the window manager, etc.
Change-Id: Ib8f5d29a5572542cc506e6d338599ab64088ce4e
17 files changed, 148 insertions, 23 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 83acb4dc816e..bb62c9e5d4cf 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1772,6 +1772,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IUserSwitchObserver observer = IUserSwitchObserver.Stub.asInterface( data.readStrongBinder()); registerUserSwitchObserver(observer); + reply.writeNoException(); return true; } @@ -1780,12 +1781,24 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM IUserSwitchObserver observer = IUserSwitchObserver.Stub.asInterface( data.readStrongBinder()); unregisterUserSwitchObserver(observer); + reply.writeNoException(); return true; } case REQUEST_BUG_REPORT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); requestBugReport(); + reply.writeNoException(); + return true; + } + + case INPUT_DISPATCHING_TIMED_OUT_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + int pid = data.readInt(); + boolean aboveSystem = data.readInt() != 0; + long res = inputDispatchingTimedOut(pid, aboveSystem); + reply.writeNoException(); + reply.writeLong(res); return true; } @@ -4082,5 +4095,19 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(pid); + data.writeInt(aboveSystem ? 1 : 0); + mRemote.transact(INPUT_DISPATCHING_TIMED_OUT_TRANSACTION, data, reply, 0); + reply.readException(); + long res = reply.readInt(); + data.recycle(); + reply.recycle(); + return res; + } + private IBinder mRemote; } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 3124671c9a45..da844efbaec9 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -363,6 +363,8 @@ public interface IActivityManager extends IInterface { public void requestBugReport() throws RemoteException; + public long inputDispatchingTimedOut(int pid, boolean aboveSystem) throws RemoteException; + /* * Private non-Binder interfaces */ @@ -616,4 +618,5 @@ public interface IActivityManager extends IInterface { int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155; int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156; int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157; + int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158; } diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java index e1c7e32bd1f9..b3d70ff56854 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalActions.java +++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java @@ -149,6 +149,9 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac mDialog = createDialog(); prepareDialog(); + WindowManager.LayoutParams attrs = mDialog.getWindow().getAttributes(); + attrs.setTitle("GlobalActions"); + mDialog.getWindow().setAttributes(attrs); mDialog.show(); mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND); } diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java index 1269433d0a6f..7e3fdbd2ff82 100644 --- a/services/java/com/android/server/am/ActiveServices.java +++ b/services/java/com/android/server/am/ActiveServices.java @@ -1850,7 +1850,7 @@ public class ActiveServices { } if (anrMessage != null) { - mAm.appNotResponding(proc, null, null, anrMessage); + mAm.appNotResponding(proc, null, null, false, anrMessage); } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index e90eef9e8682..3ef67676b812 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -970,7 +970,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (mShowDialogs) { Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, - mContext, proc, (ActivityRecord)data.get("activity")); + mContext, proc, (ActivityRecord)data.get("activity"), + msg.arg1 != 0); d.show(); proc.anrDialog = d; } else { @@ -3247,7 +3248,7 @@ public final class ActivityManagerService extends ActivityManagerNative } final void appNotResponding(ProcessRecord app, ActivityRecord activity, - ActivityRecord parent, final String annotation) { + ActivityRecord parent, boolean aboveSystem, final String annotation) { ArrayList<Integer> firstPids = new ArrayList<Integer>(5); SparseArray<Boolean> lastPids = new SparseArray<Boolean>(20); @@ -3388,6 +3389,7 @@ public final class ActivityManagerService extends ActivityManagerNative HashMap map = new HashMap(); msg.what = SHOW_NOT_RESPONDING_MSG; msg.obj = map; + msg.arg1 = aboveSystem ? 1 : 0; map.put("app", app); if (activity != null) { map.put("activity", activity); @@ -7340,6 +7342,51 @@ public final class ActivityManagerService extends ActivityManagerNative SystemProperties.set("ctl.start", "bugreport"); } + public long inputDispatchingTimedOut(int pid, boolean aboveSystem) { + if (checkCallingPermission(android.Manifest.permission.FILTER_EVENTS) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.FILTER_EVENTS); + } + + ProcessRecord proc; + + // TODO: Unify this code with ActivityRecord.keyDispatchingTimedOut(). + synchronized (this) { + synchronized (mPidsSelfLocked) { + proc = mPidsSelfLocked.get(pid); + } + if (proc != null) { + if (proc.debugging) { + return -1; + } + + if (mDidDexOpt) { + // Give more time since we were dexopting. + mDidDexOpt = false; + return -1; + } + + if (proc.instrumentationClass != null) { + Bundle info = new Bundle(); + info.putString("shortMsg", "keyDispatchingTimedOut"); + info.putString("longMsg", "Timed out while dispatching key event"); + finishInstrumentationLocked(proc, Activity.RESULT_CANCELED, info); + proc = null; + } + } + } + + if (proc != null) { + appNotResponding(proc, null, null, aboveSystem, "keyDispatchingTimedOut"); + if (proc.instrumentationClass != null || proc.usingWrapper) { + return INSTRUMENTATION_KEY_DISPATCHING_TIMEOUT; + } + } + + return KEY_DISPATCHING_TIMEOUT; + } + public void registerProcessObserver(IProcessObserver observer) { enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER, "registerProcessObserver()"); diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 6cd86fd05d44..b9f5b5b2a780 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -841,6 +841,7 @@ final class ActivityRecord { } public boolean keyDispatchingTimedOut() { + // TODO: Unify this code with ActivityManagerService.inputDispatchingTimedOut(). ActivityRecord r; ProcessRecord anrApp = null; synchronized(service) { @@ -869,8 +870,7 @@ final class ActivityRecord { } if (anrApp != null) { - service.appNotResponding(anrApp, r, this, - "keyDispatchingTimedOut"); + service.appNotResponding(anrApp, r, this, false, "keyDispatchingTimedOut"); } return true; diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 90a7abcc515d..a6dc867bc7cb 100755 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -2436,8 +2436,8 @@ final class ActivityStack { if (err == ActivityManager.START_SUCCESS) { final int userId = aInfo != null ? UserHandle.getUserId(aInfo.applicationInfo.uid) : 0; - Slog.i(TAG, "START {" + intent.toShortString(true, true, true, false) - + " u=" + userId + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)); + Slog.i(TAG, "START u" + userId + " {" + intent.toShortString(true, true, true, false) + + "} from pid " + (callerApp != null ? callerApp.pid : callingPid)); } ActivityRecord sourceRecord = null; diff --git a/services/java/com/android/server/am/AppErrorDialog.java b/services/java/com/android/server/am/AppErrorDialog.java index 0ebbe3bff88a..a9c77fc93850 100644 --- a/services/java/com/android/server/am/AppErrorDialog.java +++ b/services/java/com/android/server/am/AppErrorDialog.java @@ -23,12 +23,9 @@ import android.content.DialogInterface; import android.content.res.Resources; import android.os.Handler; import android.os.Message; -import android.util.Slog; import android.view.WindowManager; class AppErrorDialog extends BaseErrorDialog { - private final static String TAG = "AppErrorDialog"; - private final ActivityManagerService mService; private final AppErrorResult mResult; private final ProcessRecord mProc; @@ -76,7 +73,9 @@ class AppErrorDialog extends BaseErrorDialog { setTitle(res.getText(com.android.internal.R.string.aerr_title)); getWindow().addFlags(FLAG_SYSTEM_ERROR); - getWindow().setTitle("Application Error: " + app.info.processName); + WindowManager.LayoutParams attrs = getWindow().getAttributes(); + attrs.setTitle("Application Error: " + app.info.processName); + getWindow().setAttributes(attrs); if (app.persistent) { getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); } diff --git a/services/java/com/android/server/am/AppNotRespondingDialog.java b/services/java/com/android/server/am/AppNotRespondingDialog.java index b546ae7de356..58e533bf1487 100644 --- a/services/java/com/android/server/am/AppNotRespondingDialog.java +++ b/services/java/com/android/server/am/AppNotRespondingDialog.java @@ -25,8 +25,8 @@ import android.content.Intent; import android.content.res.Resources; import android.os.Handler; import android.os.Message; -import android.os.Process; import android.util.Slog; +import android.view.WindowManager; class AppNotRespondingDialog extends BaseErrorDialog { private static final String TAG = "AppNotRespondingDialog"; @@ -40,7 +40,7 @@ class AppNotRespondingDialog extends BaseErrorDialog { private final ProcessRecord mProc; public AppNotRespondingDialog(ActivityManagerService service, Context context, - ProcessRecord app, ActivityRecord activity) { + ProcessRecord app, ActivityRecord activity, boolean aboveSystem) { super(context); mService = service; @@ -91,8 +91,13 @@ class AppNotRespondingDialog extends BaseErrorDialog { } setTitle(res.getText(com.android.internal.R.string.anr_title)); + if (aboveSystem) { + getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR); + } getWindow().addFlags(FLAG_SYSTEM_ERROR); - getWindow().setTitle("Application Not Responding: " + app.info.processName); + WindowManager.LayoutParams attrs = getWindow().getAttributes(); + attrs.setTitle("Application Not Responding: " + app.info.processName); + getWindow().setAttributes(attrs); } public void onStop() { diff --git a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java index 9fb48b380ca0..d08bb101c93f 100644 --- a/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java +++ b/services/java/com/android/server/am/AppWaitingForDebuggerDialog.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.os.Message; +import android.view.WindowManager; class AppWaitingForDebuggerDialog extends BaseErrorDialog { final ActivityManagerService mService; @@ -52,7 +53,9 @@ class AppWaitingForDebuggerDialog extends BaseErrorDialog { setMessage(text.toString()); setButton(DialogInterface.BUTTON_POSITIVE, "Force Close", mHandler.obtainMessage(1, app)); setTitle("Waiting For Debugger"); - getWindow().setTitle("Waiting For Debugger: " + app.info.processName); + WindowManager.LayoutParams attrs = getWindow().getAttributes(); + attrs.setTitle("Waiting For Debugger: " + app.info.processName); + getWindow().setAttributes(attrs); } public void onStop() { diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java index d1e89bcd58fb..6ede8f865065 100644 --- a/services/java/com/android/server/am/BaseErrorDialog.java +++ b/services/java/com/android/server/am/BaseErrorDialog.java @@ -33,7 +33,9 @@ class BaseErrorDialog extends AlertDialog { getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); getWindow().setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - getWindow().setTitle("Error Dialog"); + WindowManager.LayoutParams attrs = getWindow().getAttributes(); + attrs.setTitle("Error Dialog"); + getWindow().setAttributes(attrs); setIconAttribute(R.attr.alertDialogIcon); } diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index 9f27994a77d9..95c22ec3109e 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -151,7 +151,7 @@ public class BroadcastQueue { @Override public void run() { - mService.appNotResponding(mApp, null, null, mAnnotation); + mService.appNotResponding(mApp, null, null, false, mAnnotation); } } diff --git a/services/java/com/android/server/am/FactoryErrorDialog.java b/services/java/com/android/server/am/FactoryErrorDialog.java index b19bb5ca577a..0ffb5889569b 100644 --- a/services/java/com/android/server/am/FactoryErrorDialog.java +++ b/services/java/com/android/server/am/FactoryErrorDialog.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.os.Message; +import android.view.WindowManager; class FactoryErrorDialog extends BaseErrorDialog { public FactoryErrorDialog(Context context, CharSequence msg) { @@ -30,7 +31,9 @@ class FactoryErrorDialog extends BaseErrorDialog { setButton(DialogInterface.BUTTON_POSITIVE, context.getText(com.android.internal.R.string.factorytest_reboot), mHandler.obtainMessage(0)); - getWindow().setTitle("Factory Error"); + WindowManager.LayoutParams attrs = getWindow().getAttributes(); + attrs.setTitle("Factory Error"); + getWindow().setAttributes(attrs); } public void onStop() { diff --git a/services/java/com/android/server/am/ProcessRecord.java b/services/java/com/android/server/am/ProcessRecord.java index 652fdb58b45d..7fbab044546f 100644 --- a/services/java/com/android/server/am/ProcessRecord.java +++ b/services/java/com/android/server/am/ProcessRecord.java @@ -407,7 +407,7 @@ class ProcessRecord { sb.append('u'); sb.append(userId); sb.append('a'); - sb.append(info.uid%Process.FIRST_APPLICATION_UID); + sb.append(UserHandle.getAppId(info.uid)); if (uid != info.uid) { sb.append('i'); sb.append(UserHandle.getAppId(uid) - Process.FIRST_ISOLATED_UID); diff --git a/services/java/com/android/server/wm/InputMonitor.java b/services/java/com/android/server/wm/InputMonitor.java index 61310ca19a35..d966001adb30 100644 --- a/services/java/com/android/server/wm/InputMonitor.java +++ b/services/java/com/android/server/wm/InputMonitor.java @@ -21,6 +21,7 @@ import com.android.server.input.InputApplicationHandle; import com.android.server.input.InputWindowHandle; import com.android.server.wm.WindowManagerService.AllWindowsIterator; +import android.app.ActivityManagerNative; import android.graphics.Rect; import android.os.RemoteException; import android.util.Log; @@ -89,8 +90,9 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { public long notifyANR(InputApplicationHandle inputApplicationHandle, InputWindowHandle inputWindowHandle) { AppWindowToken appWindowToken = null; + WindowState windowState = null; + boolean aboveSystem = false; synchronized (mService.mWindowMap) { - WindowState windowState = null; if (inputWindowHandle != null) { windowState = (WindowState) inputWindowHandle.windowState; if (windowState != null) { @@ -104,6 +106,12 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { if (windowState != null) { Slog.i(WindowManagerService.TAG, "Input event dispatching timed out " + "sending to " + windowState.mAttrs.getTitle()); + // Figure out whether this window is layered above system windows. + // We need to do this here to help the activity manager know how to + // layer its ANR dialog. + int systemAlertLayer = mService.mPolicy.windowTypeToLayerLw( + WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); + aboveSystem = windowState.mBaseLayer > systemAlertLayer; } else if (appWindowToken != null) { Slog.i(WindowManagerService.TAG, "Input event dispatching timed out " + "sending to application " + appWindowToken.stringName); @@ -126,6 +134,19 @@ final class InputMonitor implements InputManagerService.WindowManagerCallbacks { } } catch (RemoteException ex) { } + } else if (windowState != null) { + try { + // Notify the activity manager about the timeout and let it decide whether + // to abort dispatching or keep waiting. + long timeout = ActivityManagerNative.getDefault().inputDispatchingTimedOut( + windowState.mSession.mPid, aboveSystem); + if (timeout >= 0) { + // The activity manager declined to abort dispatching. + // Wait a bit longer and timeout again later. + return timeout; + } + } catch (RemoteException ex) { + } } return 0; // abort dispatching } diff --git a/services/java/com/android/server/wm/Session.java b/services/java/com/android/server/wm/Session.java index d84a52bf0d43..3b4c1ab5a832 100644 --- a/services/java/com/android/server/wm/Session.java +++ b/services/java/com/android/server/wm/Session.java @@ -30,8 +30,10 @@ import android.os.Binder; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.UserHandle; import android.util.Slog; import android.view.Display; import android.view.IWindow; @@ -69,8 +71,17 @@ final class Session extends IWindowSession.Stub StringBuilder sb = new StringBuilder(); sb.append("Session{"); sb.append(Integer.toHexString(System.identityHashCode(this))); - sb.append(" uid "); - sb.append(mUid); + sb.append(" "); + sb.append(mPid); + if (mUid < Process.FIRST_APPLICATION_UID) { + sb.append(":"); + sb.append(mUid); + } else { + sb.append(":u"); + sb.append(UserHandle.getUserId(mUid)); + sb.append('a'); + sb.append(UserHandle.getAppId(mUid)); + } sb.append("}"); mStringName = sb.toString(); diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 9963d14b18f0..d23448b783cf 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -1219,7 +1219,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { mLastTitle = mAttrs.getTitle(); mWasPaused = mToken.paused; mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this)) - + " " + mLastTitle + " paused=" + mWasPaused + "}"; + + " u" + UserHandle.getUserId(mSession.mUid) + + " " + mLastTitle + (mWasPaused ? " PAUSED}" : "}"); } return mStringNameCache; } |