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
diff --git a/services/java/com/android/server/am/ActiveServices.java b/services/java/com/android/server/am/ActiveServices.java
index 1269433..7e3fdbd 100644
--- a/services/java/com/android/server/am/ActiveServices.java
+++ b/services/java/com/android/server/am/ActiveServices.java
@@ -1850,7 +1850,7 @@
         }
 
         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 e90eef9..3ef6767 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -970,7 +970,8 @@
 
                     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 @@
     }
 
     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 @@
             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 @@
         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 6cd86fd..b9f5b5b 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -841,6 +841,7 @@
     }
 
     public boolean keyDispatchingTimedOut() {
+        // TODO: Unify this code with ActivityManagerService.inputDispatchingTimedOut().
         ActivityRecord r;
         ProcessRecord anrApp = null;
         synchronized(service) {
@@ -869,8 +870,7 @@
         }
         
         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 90a7abc..a6dc867 100755
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -2436,8 +2436,8 @@
 
         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 0ebbe3b..a9c77fc9 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.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 @@
 
         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 b546ae7..58e533b 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.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 @@
     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 @@
         }
 
         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 9fb48b3..d08bb10 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.DialogInterface;
 import android.os.Handler;
 import android.os.Message;
+import android.view.WindowManager;
 
 class AppWaitingForDebuggerDialog extends BaseErrorDialog {
     final ActivityManagerService mService;
@@ -52,7 +53,9 @@
         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 d1e89bc..6ede8f8 100644
--- a/services/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/java/com/android/server/am/BaseErrorDialog.java
@@ -33,7 +33,9 @@
         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 9f27994..95c22ec 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -151,7 +151,7 @@
 
         @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 b19bb5ca..0ffb588 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.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 @@
         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 652fdb5..7fbab04 100644
--- a/services/java/com/android/server/am/ProcessRecord.java
+++ b/services/java/com/android/server/am/ProcessRecord.java
@@ -407,7 +407,7 @@
             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 61310ca..d966001 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.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 @@
     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 @@
             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 @@
                 }
             } 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 d84a52b..3b4c1ab 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.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 @@
         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 9963d14..d23448b 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1219,7 +1219,8 @@
             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;
     }