Introduce "StrictMode"

This is a new public API for developers to opt-in to strict rules
about what they're allowed to do on certain threads.  (this is the
public face of the @hide dalvik.system.BlockGuard, added recently...)

In practice this will be used for developers to opt-in to declaring
that they don't want to be allowed to do various operations (such as
disk I/O or network operations) on their main UI threads.  (these
operations are often accidental, or even when they are fast come with
a good chance of being slow or very slow in some cases....)

Implementation wise, this is just a thread-local integer that has a
bitmask of the things that aren't allowed, and more bits for saying
what the violation penalty is.  The penalties, of which multiple can
be chosen, include:

  * logging
  * dropbox uploading for analysis/reporting
  * annoying dialog
  * full-on crashing

These are all only very roughly implemented at this point, but all
parts now minimally work end-to-end now, so this is a good checkpoint
commit before this gets too large.

Future CLs will polish all the above 4 penalties, including
checksumming of stacktraces and minimizing penalties for duplicate
violations.

Change-Id: Icbe61a2e950119519e7364030b10c3c28d243abe
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b3c5199..cfcac86 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -1023,6 +1023,7 @@
     static final int FINALIZE_PENDING_INTENT_MSG = 23;
     static final int POST_HEAVY_NOTIFICATION_MSG = 24;
     static final int CANCEL_HEAVY_NOTIFICATION_MSG = 25;
+    static final int SHOW_STRICT_MODE_VIOLATION_MSG = 26;
 
     AlertDialog mUidAlert;
 
@@ -1076,6 +1077,31 @@
                 
                 ensureBootCompleted();
             } break;
+            case SHOW_STRICT_MODE_VIOLATION_MSG: {
+                HashMap<String, Object> data = (HashMap<String, Object>) msg.obj;
+                synchronized (ActivityManagerService.this) {
+                    ProcessRecord proc = (ProcessRecord) data.get("app");
+                    if (proc == null) {
+                        Slog.e(TAG, "App not found when showing strict mode dialog.");
+                        break;
+                    }
+                    if (proc.crashDialog != null) {
+                        Slog.e(TAG, "App already has strict mode dialog: " + proc);
+                        return;
+                    }
+                    AppErrorResult res = (AppErrorResult) data.get("result");
+                    if (!mSleeping && !mShuttingDown) {
+                        Dialog d = new StrictModeViolationDialog(mContext, res, proc);
+                        d.show();
+                        proc.crashDialog = d;
+                    } else {
+                        // The device is asleep, so just pretend that the user
+                        // saw a crash dialog and hit "force quit".
+                        res.set(0);
+                    }
+                }
+                ensureBootCompleted();
+            } break;
             case SHOW_FACTORY_ERROR_MSG: {
                 Dialog d = new FactoryErrorDialog(
                     mContext, msg.getData().getCharSequence("msg"));
@@ -9311,6 +9337,30 @@
         crashApplication(r, crashInfo);
     }
 
+    public void handleApplicationStrictModeViolation(
+        IBinder app, ApplicationErrorReport.CrashInfo crashInfo) {
+        ProcessRecord r = findAppProcess(app);
+        // TODO: implement
+        Log.w(TAG, "handleApplicationStrictModeViolation.");
+
+        AppErrorResult result = new AppErrorResult();
+        synchronized (this) {
+            final long origId = Binder.clearCallingIdentity();
+
+            Message msg = Message.obtain();
+            msg.what = SHOW_STRICT_MODE_VIOLATION_MSG;
+            HashMap<String, Object> data = new HashMap<String, Object>();
+            data.put("result", result);
+            data.put("app", r);
+            msg.obj = data;
+            mHandler.sendMessage(msg);
+
+            Binder.restoreCallingIdentity(origId);
+        }
+        int res = result.get();
+        Log.w(TAG, "handleApplicationStrictModeViolation; res=" + res);
+    }
+
     /**
      * Used by {@link Log} via {@link com.android.internal.os.RuntimeInit} to report serious errors.
      * @param app object of the crashing app, null for the system server