Merge "Only install after MCS success" into gingerbread
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 1fe85e6..9a55a6f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -37,6 +37,7 @@
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.ServiceManager;
+import android.os.StrictMode;
 import android.text.TextUtils;
 import android.util.Config;
 import android.util.Log;
@@ -1056,8 +1057,8 @@
             data.enforceInterface(IActivityManager.descriptor);
             IBinder app = data.readStrongBinder();
             int violationMask = data.readInt();
-            ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
-            handleApplicationStrictModeViolation(app, violationMask, ci);
+            StrictMode.ViolationInfo info = new StrictMode.ViolationInfo(data);
+            handleApplicationStrictModeViolation(app, violationMask, info);
             reply.writeNoException();
             return true;
         }
@@ -2571,14 +2572,14 @@
 
     public void handleApplicationStrictModeViolation(IBinder app,
             int violationMask,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
+            StrictMode.ViolationInfo info) throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(app);
         data.writeInt(violationMask);
-        crashInfo.writeToParcel(data, 0);
+        info.writeToParcel(data, 0);
         mRemote.transact(HANDLE_APPLICATION_STRICT_MODE_VIOLATION_TRANSACTION, data, reply, 0);
         reply.readException();
         reply.recycle();
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 30815c3..8f940d5 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -24,6 +24,7 @@
 import android.content.pm.ResolveInfo;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.provider.Settings;
 import android.util.Printer;
@@ -74,18 +75,15 @@
     public static final int TYPE_BATTERY = 3;
 
     /**
-     * An error report about a StrictMode violation.
-     */
-    public static final int TYPE_STRICT_MODE_VIOLATION = 4;
-
-    /**
-     * An error report about a StrictMode violation.
+     * A report from a user to a developer about a running service that the
+     * user doesn't think should be running.
      */
     public static final int TYPE_RUNNING_SERVICE = 5;
 
     /**
      * Type of this report. Can be one of {@link #TYPE_NONE},
-     * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, or {@link #TYPE_BATTERY}.
+     * {@link #TYPE_CRASH}, {@link #TYPE_ANR}, {@link #TYPE_BATTERY},
+     * or {@link #TYPE_RUNNING_SERVICE}.
      */
     public int type;
 
@@ -133,7 +131,7 @@
      * of BatteryInfo; otherwise null.
      */
     public BatteryInfo batteryInfo;
-    
+
     /**
      * If this report is of type {@link #TYPE_RUNNING_SERVICE}, contains an instance
      * of RunningServiceInfo; otherwise null.
@@ -278,10 +276,6 @@
 
     /**
      * Describes an application crash.
-     *
-     * <p>This is also used to marshal around stack traces of ANRs and
-     * StrictMode violations which aren't necessarily crashes, but have
-     * a lot in common.
      */
     public static class CrashInfo {
         /**
@@ -320,12 +314,6 @@
         public String stackTrace;
 
         /**
-         * For StrictMode violations, the wall time duration of the
-         * violation, when known.
-         */
-        public long durationMillis = -1;
-
-        /**
          * Create an uninitialized instance of CrashInfo.
          */
         public CrashInfo() {
@@ -368,7 +356,6 @@
             throwMethodName = in.readString();
             throwLineNumber = in.readInt();
             stackTrace = in.readString();
-            durationMillis = in.readLong();
         }
 
         /**
@@ -382,7 +369,6 @@
             dest.writeString(throwMethodName);
             dest.writeInt(throwLineNumber);
             dest.writeString(stackTrace);
-            dest.writeLong(durationMillis);
         }
 
         /**
@@ -396,9 +382,6 @@
             pw.println(prefix + "throwMethodName: " + throwMethodName);
             pw.println(prefix + "throwLineNumber: " + throwLineNumber);
             pw.println(prefix + "stackTrace: " + stackTrace);
-            if (durationMillis != -1) {
-                pw.println(prefix + "durationMillis: " + durationMillis);
-            }
         }
     }
 
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 20c9a80..81b28b9 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -19,10 +19,10 @@
 import android.content.ComponentName;
 import android.content.ContentProviderNative;
 import android.content.IContentProvider;
+import android.content.IIntentReceiver;
+import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.IIntentSender;
-import android.content.IIntentReceiver;
 import android.content.IntentSender;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ConfigurationInfo;
@@ -31,14 +31,15 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
+import android.os.Bundle;
 import android.os.Debug;
-import android.os.RemoteException;
 import android.os.IBinder;
 import android.os.IInterface;
 import android.os.Parcel;
-import android.os.Parcelable;
 import android.os.ParcelFileDescriptor;
-import android.os.Bundle;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.StrictMode;
 
 import java.util.List;
 
@@ -260,7 +261,7 @@
     // bit violated and penalty bits to be executed by the
     // ActivityManagerService remaining set.
     public void handleApplicationStrictModeViolation(IBinder app, int violationMask,
-            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
+            StrictMode.ViolationInfo crashInfo) throws RemoteException;
 
     /*
      * This will deliver the specified signal to all the persistent processes. Currently only 
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index d4b0500..ac12e10 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -18,6 +18,7 @@
 import android.app.ActivityManagerNative;
 import android.app.ApplicationErrorReport;
 import android.util.Log;
+import android.util.Printer;
 
 import com.android.internal.os.RuntimeInit;
 
@@ -97,9 +98,9 @@
      * via Parcel.writeNoException() (amusingly) where the caller can
      * choose how to react.
      */
-    private static final ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>> gatheredViolations =
-            new ThreadLocal<ArrayList<ApplicationErrorReport.CrashInfo>>() {
-        @Override protected ArrayList<ApplicationErrorReport.CrashInfo> initialValue() {
+    private static final ThreadLocal<ArrayList<ViolationInfo>> gatheredViolations =
+            new ThreadLocal<ArrayList<ViolationInfo>>() {
+        @Override protected ArrayList<ViolationInfo> initialValue() {
             // Starts null to avoid unnecessary allocations when
             // checking whether there are any violations or not in
             // hasGatheredViolations() below.
@@ -240,7 +241,9 @@
             if ((mPolicyMask & DISALLOW_DISK_WRITE) == 0) {
                 return;
             }
-            startHandlingViolationException(new StrictModeDiskWriteViolation(mPolicyMask));
+            BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
         }
 
         // Part of BlockGuard.Policy interface:
@@ -248,7 +251,9 @@
             if ((mPolicyMask & DISALLOW_DISK_READ) == 0) {
                 return;
             }
-            startHandlingViolationException(new StrictModeDiskReadViolation(mPolicyMask));
+            BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
         }
 
         // Part of BlockGuard.Policy interface:
@@ -256,7 +261,9 @@
             if ((mPolicyMask & DISALLOW_NETWORK) == 0) {
                 return;
             }
-            startHandlingViolationException(new StrictModeNetworkViolation(mPolicyMask));
+            BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
+            e.fillInStackTrace();
+            startHandlingViolationException(e);
         }
 
         public void setPolicyMask(int policyMask) {
@@ -269,31 +276,70 @@
         // thread and, if so, uses it to roughly measure how long the
         // violation took.
         void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
-            e.fillInStackTrace();
-            final ApplicationErrorReport.CrashInfo crashInfo = new ApplicationErrorReport.CrashInfo(e);
-            crashInfo.durationMillis = -1;  // unknown
-            final int savedPolicy = mPolicyMask;
+            final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
+            info.violationUptimeMillis = SystemClock.uptimeMillis();
+            handleViolationWithTimingAttempt(info);
+        }
 
+        private static final ThreadLocal<ArrayList<ViolationInfo>> violationsBeingTimed =
+                new ThreadLocal<ArrayList<ViolationInfo>>() {
+            @Override protected ArrayList<ViolationInfo> initialValue() {
+                return new ArrayList<ViolationInfo>();
+            }
+        };
+
+        // Attempts to fill in the provided ViolationInfo's
+        // durationMillis field if this thread has a Looper we can use
+        // to measure with.  We measure from the time of violation
+        // until the time the looper is idle again (right before
+        // the next epoll_wait)
+        void handleViolationWithTimingAttempt(final ViolationInfo info) {
             Looper looper = Looper.myLooper();
+
+            // Without a Looper, we're unable to time how long the
+            // violation takes place.  This case should be rare, as
+            // most users will care about timing violations that
+            // happen on their main UI thread.  Note that this case is
+            // also hit when a violation takes place in a Binder
+            // thread, in "gather" mode.  In this case, the duration
+            // of the violation is computed by the ultimate caller and
+            // its Looper, if any.
+            // TODO: if in gather mode, ignore Looper.myLooper() and always
+            //       go into this immediate mode?
             if (looper == null) {
-                // Without a Looper, we're unable to time how long the
-                // violation takes place.  This case should be rare,
-                // as most users will care about timing violations
-                // that happen on their main UI thread.
-                handleViolation(crashInfo, savedPolicy);
-            } else {
-                MessageQueue queue = Looper.myQueue();
-                final long violationTime = SystemClock.uptimeMillis();
-                queue.addIdleHandler(new MessageQueue.IdleHandler() {
-                        public boolean queueIdle() {
-                            long afterViolationTime = SystemClock.uptimeMillis();
-                            crashInfo.durationMillis = afterViolationTime - violationTime;
-                            handleViolation(crashInfo, savedPolicy);
-                            return false;  // remove this idle handler from the array
-                        }
-                    });
+                info.durationMillis = -1;  // unknown (redundant, already set)
+                handleViolation(info);
+                return;
             }
 
+            MessageQueue queue = Looper.myQueue();
+            final ArrayList<ViolationInfo> records = violationsBeingTimed.get();
+            if (records.size() >= 10) {
+                // Not worth measuring.  Too many offenses in one loop.
+                return;
+            }
+            records.add(info);
+            if (records.size() > 1) {
+                // There's already been a violation this loop, so we've already
+                // registered an idle handler to process the list of violations
+                // at the end of this Looper's loop.
+                return;
+            }
+
+            queue.addIdleHandler(new MessageQueue.IdleHandler() {
+                    public boolean queueIdle() {
+                        long loopFinishTime = SystemClock.uptimeMillis();
+                        for (int n = 0; n < records.size(); ++n) {
+                            ViolationInfo v = records.get(n);
+                            v.violationNumThisLoop = n + 1;
+                            v.durationMillis =
+                                    (int) (loopFinishTime - v.violationUptimeMillis);
+                            handleViolation(v);
+                        }
+                        records.clear();
+                        return false;  // remove this idle handler from the array
+                    }
+                });
         }
 
         // Note: It's possible (even quite likely) that the
@@ -301,37 +347,35 @@
         // violation fired and now (after the violating code ran) due
         // to people who push/pop temporary policy in regions of code,
         // hence the policy being passed around.
-        void handleViolation(
-            final ApplicationErrorReport.CrashInfo crashInfo,
-            int policy) {
-            if (crashInfo.stackTrace == null) {
-                Log.d(TAG, "unexpected null stacktrace");
+        void handleViolation(final ViolationInfo info) {
+            if (info == null || info.crashInfo == null || info.crashInfo.stackTrace == null) {
+                Log.wtf(TAG, "unexpected null stacktrace");
                 return;
             }
 
-            if (LOG_V) Log.d(TAG, "handleViolation; policy=" + policy);
+            if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy);
 
-            if ((policy & PENALTY_GATHER) != 0) {
-                ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get();
+            if ((info.policy & PENALTY_GATHER) != 0) {
+                ArrayList<ViolationInfo> violations = gatheredViolations.get();
                 if (violations == null) {
-                    violations = new ArrayList<ApplicationErrorReport.CrashInfo>(1);
+                    violations = new ArrayList<ViolationInfo>(1);
                     gatheredViolations.set(violations);
                 } else if (violations.size() >= 5) {
                     // Too many.  In a loop or something?  Don't gather them all.
                     return;
                 }
-                for (ApplicationErrorReport.CrashInfo previous : violations) {
-                    if (crashInfo.stackTrace.equals(previous.stackTrace)) {
+                for (ViolationInfo previous : violations) {
+                    if (info.crashInfo.stackTrace.equals(previous.crashInfo.stackTrace)) {
                         // Duplicate. Don't log.
                         return;
                     }
                 }
-                violations.add(crashInfo);
+                violations.add(info);
                 return;
             }
 
             // Not perfect, but fast and good enough for dup suppression.
-            Integer crashFingerprint = crashInfo.stackTrace.hashCode();
+            Integer crashFingerprint = info.crashInfo.stackTrace.hashCode();
             long lastViolationTime = 0;
             if (mLastViolationTime.containsKey(crashFingerprint)) {
                 lastViolationTime = mLastViolationTime.get(crashFingerprint);
@@ -341,13 +385,13 @@
             long timeSinceLastViolationMillis = lastViolationTime == 0 ?
                     Long.MAX_VALUE : (now - lastViolationTime);
 
-            if ((policy & PENALTY_LOG) != 0 &&
+            if ((info.policy & PENALTY_LOG) != 0 &&
                 timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
-                if (crashInfo.durationMillis != -1) {
+                if (info.durationMillis != -1) {
                     Log.d(TAG, "StrictMode policy violation; ~duration=" +
-                          crashInfo.durationMillis + " ms: " + crashInfo.stackTrace);
+                          info.durationMillis + " ms: " + info.crashInfo.stackTrace);
                 } else {
-                    Log.d(TAG, "StrictMode policy violation: " + crashInfo.stackTrace);
+                    Log.d(TAG, "StrictMode policy violation: " + info.crashInfo.stackTrace);
                 }
             }
 
@@ -355,20 +399,20 @@
             // subset of the original StrictMode policy bitmask, with
             // only the bit violated and penalty bits to be executed
             // by the ActivityManagerService remaining set.
-            int violationMask = 0;
+            int violationMaskSubset = 0;
 
-            if ((policy & PENALTY_DIALOG) != 0 &&
+            if ((info.policy & PENALTY_DIALOG) != 0 &&
                 timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
-                violationMask |= PENALTY_DIALOG;
+                violationMaskSubset |= PENALTY_DIALOG;
             }
 
-            if ((policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
-                violationMask |= PENALTY_DROPBOX;
+            if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
+                violationMaskSubset |= PENALTY_DROPBOX;
             }
 
-            if (violationMask != 0) {
-                int violationBit = parseViolationFromMessage(crashInfo.exceptionMessage);
-                violationMask |= violationBit;
+            if (violationMaskSubset != 0) {
+                int violationBit = parseViolationFromMessage(info.crashInfo.exceptionMessage);
+                violationMaskSubset |= violationBit;
                 final int savedPolicy = getThreadBlockingPolicy();
                 try {
                     // First, remove any policy before we call into the Activity Manager,
@@ -379,8 +423,8 @@
 
                     ActivityManagerNative.getDefault().handleApplicationStrictModeViolation(
                         RuntimeInit.getApplicationObject(),
-                        violationMask,
-                        crashInfo);
+                        violationMaskSubset,
+                        info);
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
                 } finally {
@@ -389,7 +433,7 @@
                 }
             }
 
-            if ((policy & PENALTY_DEATH) != 0) {
+            if ((info.policy & PENALTY_DEATH) != 0) {
                 System.err.println("StrictMode policy violation with POLICY_DEATH; shutting down.");
                 Process.killProcess(Process.myPid());
                 System.exit(10);
@@ -417,7 +461,7 @@
      * Called from Parcel.writeNoException()
      */
     /* package */ static void writeGatheredViolationsToParcel(Parcel p) {
-        ArrayList<ApplicationErrorReport.CrashInfo> violations = gatheredViolations.get();
+        ArrayList<ViolationInfo> violations = gatheredViolations.get();
         if (violations == null) {
             p.writeInt(0);
         } else {
@@ -439,35 +483,21 @@
      */
     /* package */ static void readAndHandleBinderCallViolations(Parcel p) {
         // Our own stack trace to append
-        Exception e = new LogStackTrace();
         StringWriter sw = new StringWriter();
-        e.printStackTrace(new PrintWriter(sw));
+        new LogStackTrace().printStackTrace(new PrintWriter(sw));
         String ourStack = sw.toString();
 
         int policyMask = getThreadBlockingPolicy();
+        boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
 
         int numViolations = p.readInt();
         for (int i = 0; i < numViolations; ++i) {
             if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call.  i=" + i);
-            ApplicationErrorReport.CrashInfo crashInfo = new ApplicationErrorReport.CrashInfo(p);
-            crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack;
-
-            // Unlike the in-process violations in which case we
-            // trigger an error _before_ the thing occurs, in this
-            // case the violating thing has already occurred, so we
-            // can't use our heuristic of waiting for the next event
-            // loop idle cycle to measure the approximate violation
-            // duration.  Instead, just skip that step and use -1
-            // (unknown duration) for now.
-            // TODO: keep a thread-local on remote process of first
-            // violation time's uptimeMillis, and when writing that
-            // back out in Parcel reply, include in the header the
-            // violation time and use it here.
-            crashInfo.durationMillis = -1;
-
+            ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
+            info.crashInfo.stackTrace += "# via Binder call with stack:\n" + ourStack;
             BlockGuard.Policy policy = BlockGuard.getThreadPolicy();
             if (policy instanceof AndroidBlockGuardPolicy) {
-                ((AndroidBlockGuardPolicy) policy).handleViolation(crashInfo, policyMask);
+                ((AndroidBlockGuardPolicy) policy).handleViolationWithTimingAttempt(info);
             }
         }
     }
@@ -483,4 +513,113 @@
     private static void onBinderStrictModePolicyChange(int newPolicy) {
         setBlockGuardPolicy(newPolicy);
     }
+
+    /**
+     * Parcelable that gets sent in Binder call headers back to callers
+     * to report violations that happened during a cross-process call.
+     *
+     * @hide
+     */
+    public static class ViolationInfo {
+        /**
+         * Stack and other stuff info.
+         */
+        public final ApplicationErrorReport.CrashInfo crashInfo;
+
+        /**
+         * The strict mode policy mask at the time of violation.
+         */
+        public final int policy;
+
+        /**
+         * The wall time duration of the violation, when known.  -1 when
+         * not known.
+         */
+        public int durationMillis = -1;
+
+        /**
+         * Which violation number this was (1-based) since the last Looper loop,
+         * from the perspective of the root caller (if it crossed any processes
+         * via Binder calls).  The value is 0 if the root caller wasn't on a Looper
+         * thread.
+         */
+        public int violationNumThisLoop;
+
+        /**
+         * The time (in terms of SystemClock.uptimeMillis()) that the
+         * violation occurred.
+         */
+        public long violationUptimeMillis;
+
+        /**
+         * Create an uninitialized instance of ViolationInfo
+         */
+        public ViolationInfo() {
+            crashInfo = null;
+            policy = 0;
+        }
+
+        /**
+         * Create an instance of ViolationInfo initialized from an exception.
+         */
+        public ViolationInfo(Throwable tr, int policy) {
+            crashInfo = new ApplicationErrorReport.CrashInfo(tr);
+            violationUptimeMillis = SystemClock.uptimeMillis();
+            this.policy = policy;
+        }
+
+        /**
+         * Create an instance of ViolationInfo initialized from a Parcel.
+         */
+        public ViolationInfo(Parcel in) {
+            this(in, false);
+        }
+
+        /**
+         * Create an instance of ViolationInfo initialized from a Parcel.
+         *
+         * @param unsetGatheringBit if true, the caller is the root caller
+         *   and the gathering penalty should be removed.
+         */
+        public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
+            crashInfo = new ApplicationErrorReport.CrashInfo(in);
+            int rawPolicy = in.readInt();
+            if (unsetGatheringBit) {
+                policy = rawPolicy & ~PENALTY_GATHER;
+            } else {
+                policy = rawPolicy;
+            }
+            durationMillis = in.readInt();
+            violationNumThisLoop = in.readInt();
+            violationUptimeMillis = in.readLong();
+        }
+
+        /**
+         * Save a ViolationInfo instance to a parcel.
+         */
+        public void writeToParcel(Parcel dest, int flags) {
+            crashInfo.writeToParcel(dest, flags);
+            dest.writeInt(policy);
+            dest.writeInt(durationMillis);
+            dest.writeInt(violationNumThisLoop);
+            dest.writeLong(violationUptimeMillis);
+        }
+
+
+        /**
+         * Dump a ViolationInfo instance to a Printer.
+         */
+        public void dump(Printer pw, String prefix) {
+            crashInfo.dump(pw, prefix);
+            pw.println(prefix + "policy: " + policy);
+            if (durationMillis != -1) {
+                pw.println(prefix + "durationMillis: " + durationMillis);
+            }
+            if (violationNumThisLoop != 0) {
+                pw.println(prefix + "violationNumThisLoop: " + violationNumThisLoop);
+            }
+            pw.println(prefix + "violationUptimeMillis: " + violationUptimeMillis);
+        }
+
+    }
 }
diff --git a/core/java/android/widget/BaseExpandableListAdapter.java b/core/java/android/widget/BaseExpandableListAdapter.java
index 396b7ae..b4d6ad7 100644
--- a/core/java/android/widget/BaseExpandableListAdapter.java
+++ b/core/java/android/widget/BaseExpandableListAdapter.java
@@ -43,14 +43,14 @@
     }
     
     /**
-     * {@see DataSetObservable#notifyInvalidated()}
+     * @see DataSetObservable#notifyInvalidated()
      */
     public void notifyDataSetInvalidated() {
         mDataSetObservable.notifyInvalidated();
     }
     
     /**
-     * {@see DataSetObservable#notifyChanged()}
+     * @see DataSetObservable#notifyChanged()
      */
     public void notifyDataSetChanged() {
         mDataSetObservable.notifyChanged();
diff --git a/core/java/android/widget/HeterogeneousExpandableList.java b/core/java/android/widget/HeterogeneousExpandableList.java
index 1292733..e7e0933 100644
--- a/core/java/android/widget/HeterogeneousExpandableList.java
+++ b/core/java/android/widget/HeterogeneousExpandableList.java
@@ -23,12 +23,13 @@
  * Additional methods that when implemented make an
  * {@link ExpandableListAdapter} take advantage of the {@link Adapter} view type
  * mechanism.
- * 
- * An {@link ExpandableListAdapter} declares one view type for its group items
+ * <p>
+ * An {@link ExpandableListAdapter} declares it has one view type for its group items
  * and one view type for its child items. Although adapted for most {@link ExpandableListView}s,
- * these values should be tuned heterogeneous {@link ExpandableListView}s. Lists that contain
- * different types of group and/or child item views, should use an adapter that implements this
- * interface. This way, the recycled views that will be provided to
+ * these values should be tuned for heterogeneous {@link ExpandableListView}s.
+ * </p>
+ * Lists that contain different types of group and/or child item views, should use an adapter that
+ * implements this interface. This way, the recycled views that will be provided to
  * {@link android.widget.ExpandableListAdapter#getGroupView(int, boolean, View, ViewGroup)}
  * and
  * {@link android.widget.ExpandableListAdapter#getChildView(int, int, boolean, View, ViewGroup)}
@@ -48,7 +49,7 @@
      *         . Note: Integers must be in the range 0 to {@link #getGroupTypeCount} - 1.
      *         {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
      * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
-     * @see getGroupTypeCount()
+     * @see #getGroupTypeCount()
      */
     int getGroupType(int groupPosition);
 
@@ -65,7 +66,7 @@
      *         Note: Integers must be in the range 0 to {@link #getChildTypeCount} - 1.
      *         {@link android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE} can also be returned.
      * @see android.widget.Adapter#IGNORE_ITEM_VIEW_TYPE
-     * @see getChildTypeCount()
+     * @see #getChildTypeCount()
      */
     int getChildType(int groupPosition, int childPosition);
 
@@ -78,13 +79,11 @@
      * . If the adapter always returns the same type of View for all group items, this method should
      * return 1.
      * </p>
-     * <p>
      * This method will only be called when the adapter is set on the {@link AdapterView}.
-     * </p>
      * 
      * @return The number of types of group Views that will be created by this adapter.
-     * @see getChildTypeCount()
-     * @see getGroupType()
+     * @see #getChildTypeCount()
+     * @see #getGroupType(int)
      */
     int getGroupTypeCount();
 
@@ -97,13 +96,11 @@
      * , for any group. If the adapter always returns the same type of View for
      * all child items, this method should return 1.
      * </p>
-     * <p>
      * This method will only be called when the adapter is set on the {@link AdapterView}.
-     * </p>
      * 
      * @return The total number of types of child Views that will be created by this adapter.
-     * @see getGroupTypeCount()
-     * @see getChildType()
+     * @see #getGroupTypeCount()
+     * @see #getChildType(int, int)
      */
     int getChildTypeCount();
 }
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
index cdaefc8..ad8d444 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java
@@ -91,30 +91,30 @@
     //                                      DISCONNECTING, DISCONNECTED, UNKNOWN
     private void waitForNetworkState(int networkType, State expectedState, long timeout) {
         long startTime = System.currentTimeMillis();
-        // In case the broadcast is already sent out, no need to wait
-        if (cmActivity.mCM.getNetworkInfo(networkType).getState() == expectedState) {
-            return;
-        } else {
-            while (true) {
-                if ((System.currentTimeMillis() - startTime) > timeout) {
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (cmActivity.mCM.getNetworkInfo(networkType).getState() != expectedState) {
                     assertFalse("Wait for network state timeout", true);
+                } else {
+                    // the broadcast has been sent out. the state has been changed.
+                    return;
                 }
-                Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
-                        " to be " + expectedState.toString());
-                synchronized (cmActivity.connectivityObject) {
-                    try {
-                        cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT);
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
-                    }
-                    if ((cmActivity.mNetworkInfo.getType() != networkType) ||
-                        (cmActivity.mNetworkInfo.getState() != expectedState)) {
-                        Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() +
-                                "is: " + cmActivity.mNetworkInfo.getState());
-                        continue;
-                    }
-                    break;
+            }
+            Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
+                    " to be " + expectedState.toString());
+            synchronized (cmActivity.connectivityObject) {
+                try {
+                    cmActivity.connectivityObject.wait(STATE_TRANSITION_SHORT_TIMEOUT);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
                 }
+                if ((cmActivity.mNetworkInfo.getType() != networkType) ||
+                    (cmActivity.mNetworkInfo.getState() != expectedState)) {
+                    Log.v(LOG_TAG, "network state for " + cmActivity.mNetworkInfo.getType() +
+                            "is: " + cmActivity.mNetworkInfo.getState());
+                    continue;
+                }
+                break;
             }
         }
     }
@@ -123,26 +123,26 @@
     //                      WIFI_STATE_ENALBING, WIFI_STATE_UNKNOWN
     private void waitForWifiState(int expectedState, long timeout) {
         long startTime = System.currentTimeMillis();
-        if (cmActivity.mWifiState == expectedState) {
-            return;
-        } else {
-            while (true) {
-                if ((System.currentTimeMillis() - startTime) > timeout) {
+        while (true) {
+            if ((System.currentTimeMillis() - startTime) > timeout) {
+                if (cmActivity.mWifiState != expectedState) {
                     assertFalse("Wait for Wifi state timeout", true);
+                } else {
+                    return;
                 }
-                Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
-                synchronized (cmActivity.wifiObject) {
-                    try {
-                        cmActivity.wifiObject.wait(5*1000);
-                    } catch (InterruptedException e) {
-                        e.printStackTrace();
-                    }
-                    if (cmActivity.mWifiState != expectedState) {
-                        Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState());
-                        continue;
-                    }
-                    break;
+            }
+            Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
+            synchronized (cmActivity.wifiObject) {
+                try {
+                    cmActivity.wifiObject.wait(5*1000);
+                } catch (InterruptedException e) {
+                    e.printStackTrace();
                 }
+                if (cmActivity.mWifiState != expectedState) {
+                    Log.v(LOG_TAG, "Wifi state is: " + cmActivity.mWifiNetworkInfo.getState());
+                    continue;
+                }
+                break;
             }
         }
     }
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 7e2f8a0..1d6ab25 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -450,8 +450,8 @@
 to match the device density.</li>
         </ul>
         <p><em>Added in API Level 4.</em></p>
-        <p>There is thus a 4:3 scaling factor between each density, so a 9x9 bitmap
-         in ldpi is 12x12 in mdpi and 16x16 in hdpi.</p>
+        <p>There is thus a 3:4:6 scaling ratio between the three densities, so a 9x9 bitmap
+         in ldpi is 12x12 in mdpi and 18x18 in hdpi.</p>
         <p>When Android selects which resource files to use,
          it handles screen density differently than the other qualifiers.
          In step 1 of <a href="#BestMatch">How Android finds the best
@@ -895,7 +895,7 @@
 drawable-port-notouch-12key/
 </pre>
 <p class="note"><strong>Exception:</strong> Screen pixel density is the one qualifier that is not
-eliminated due to a contradiction. Even though the screen density of the device is mdpi,
+eliminated due to a contradiction. Even though the screen density of the device is hdpi,
 <code>drawable-port-ldpi/</code> is not eliminated because every screen density is
 considered to be a match at this point. More information is available in the <a
 href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
@@ -922,9 +922,8 @@
 <strike>drawable-port-notouch-12key/</strike>
 </pre>
 <p class="note"><strong>Exception:</strong> If the qualifier in question is screen pixel density,
-Android
-selects the option that most closely matches the device, and the selection process is complete.
-In general, Android prefers scaling down a larger original image to scaling  up a smaller
+Android selects the option that most closely matches the device screen density.
+In general, Android prefers scaling down a larger original image to scaling up a smaller
 original image. See <a href="{@docRoot}guide/practices/screens_support.html">Supporting Multiple
 Screens</a>.</p>
   </li>
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 9974f2f..964700b 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -1,6 +1,5 @@
 /*
  * Copyright (C) 2008 The Android Open Source Project
- * Copyright (C) 2008 HTC Inc.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index cfc17a5..54adca8 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, The Android Open Source Project
  **
  ** Licensed under the Apache License, Version 2.0 (the "License");
  ** you may not use this file except in compliance with the License.
diff --git a/include/media/PVMediaRecorder.h b/include/media/PVMediaRecorder.h
index f75d80d..c091c39 100644
--- a/include/media/PVMediaRecorder.h
+++ b/include/media/PVMediaRecorder.h
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, The Android Open Source Project
  **
  ** Licensed under the Apache License, Version 2.0 (the "License");
  ** you may not use this file except in compliance with the License.
diff --git a/include/ui/InputReader.h b/include/ui/InputReader.h
index d7ec8ea..6bf1bfa 100644
--- a/include/ui/InputReader.h
+++ b/include/ui/InputReader.h
@@ -210,7 +210,7 @@
  * IMPORTANT INVARIANT:
  *     Because the policy and dispatcher can potentially block or cause re-entrance into
  *     the input reader, the input reader never calls into other components while holding
- *     an exclusive internal lock.
+ *     an exclusive internal lock whenever re-entrance can happen.
  */
 class InputReader : public InputReaderInterface, private InputReaderContext {
 public:
@@ -414,6 +414,8 @@
     virtual int32_t getMetaState();
 
 private:
+    Mutex mLock;
+
     struct KeyDown {
         int32_t keyCode;
         int32_t scanCode;
@@ -423,17 +425,22 @@
     uint32_t mSources;
     int32_t mKeyboardType;
 
-    Vector<KeyDown> mKeyDowns; // keys that are down
-    int32_t mMetaState;
-    nsecs_t mDownTime; // time of most recent key down
+    struct LockedState {
+        Vector<KeyDown> keyDowns; // keys that are down
+        int32_t metaState;
+        nsecs_t downTime; // time of most recent key down
+    } mLocked;
 
-    void initialize();
+    void initializeLocked();
 
     bool isKeyboardOrGamepadKey(int32_t scanCode);
+
     void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
             uint32_t policyFlags);
+    void applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags,
+            bool down, int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime);
 
-    ssize_t findKeyDown(int32_t scanCode);
+    ssize_t findKeyDownLocked(int32_t scanCode);
 };
 
 
@@ -451,6 +458,8 @@
     // Amount that trackball needs to move in order to generate a key event.
     static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6;
 
+    Mutex mLock;
+
     int32_t mAssociatedDisplayId;
 
     struct Accumulator {
@@ -475,17 +484,21 @@
         }
     } mAccumulator;
 
-    bool mDown;
-    nsecs_t mDownTime;
-
     float mXScale;
     float mYScale;
     float mXPrecision;
     float mYPrecision;
 
-    void initialize();
+    struct LockedState {
+        bool down;
+        nsecs_t downTime;
+    } mLocked;
+
+    void initializeLocked();
 
     void sync(nsecs_t when);
+    void applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
+            PointerCoords* pointerCoords, nsecs_t downTime);
 };
 
 
@@ -509,6 +522,8 @@
      * (This is limited by our use of BitSet32 to track pointer assignments.) */
     static const uint32_t MAX_POINTER_ID = 31;
 
+    Mutex mLock;
+
     struct VirtualKey {
         int32_t keyCode;
         int32_t scanCode;
@@ -561,7 +576,6 @@
     };
 
     int32_t mAssociatedDisplayId;
-    Vector<VirtualKey> mVirtualKeys;
 
     // Immutable configuration parameters.
     struct Parameters {
@@ -583,67 +597,65 @@
         RawAbsoluteAxisInfo orientation;
     } mAxes;
 
-    // The surface orientation and width and height set by configureSurface().
-    int32_t mSurfaceOrientation;
-    int32_t mSurfaceWidth, mSurfaceHeight;
-
-    // Translation and scaling factors, orientation-independent.
-    int32_t mXOrigin;
-    float mXScale;
-    float mXPrecision;
-
-    int32_t mYOrigin;
-    float mYScale;
-    float mYPrecision;
-
-    int32_t mPressureOrigin;
-    float mPressureScale;
-
-    int32_t mSizeOrigin;
-    float mSizeScale;
-
-    float mOrientationScale;
-
-    // Oriented motion ranges for input device info.
-    struct OrientedRanges {
-        InputDeviceInfo::MotionRange x;
-        InputDeviceInfo::MotionRange y;
-        InputDeviceInfo::MotionRange pressure;
-        InputDeviceInfo::MotionRange size;
-        InputDeviceInfo::MotionRange touchMajor;
-        InputDeviceInfo::MotionRange touchMinor;
-        InputDeviceInfo::MotionRange toolMajor;
-        InputDeviceInfo::MotionRange toolMinor;
-        InputDeviceInfo::MotionRange orientation;
-    } mOrientedRanges;
-
-    // Oriented dimensions and precision.
-    float mOrientedSurfaceWidth, mOrientedSurfaceHeight;
-    float mOrientedXPrecision, mOrientedYPrecision;
-
-    // The touch data of the current sample being processed.
+    // Current and previous touch sample data.
     TouchData mCurrentTouch;
-
-    // The touch data of the previous sample that was processed.  This is updated
-    // incrementally while the current sample is being processed.
     TouchData mLastTouch;
 
     // The time the primary pointer last went down.
     nsecs_t mDownTime;
 
-    struct CurrentVirtualKeyState {
-        bool down;
-        nsecs_t downTime;
-        int32_t keyCode;
-        int32_t scanCode;
-    } mCurrentVirtualKey;
+    struct LockedState {
+        Vector<VirtualKey> virtualKeys;
 
-    // Lock for virtual key state.
-    Mutex mVirtualKeyLock; // methods use "Lvk" suffix
+        // The surface orientation and width and height set by configureSurfaceLocked().
+        int32_t surfaceOrientation;
+        int32_t surfaceWidth, surfaceHeight;
+
+        // Translation and scaling factors, orientation-independent.
+        int32_t xOrigin;
+        float xScale;
+        float xPrecision;
+
+        int32_t yOrigin;
+        float yScale;
+        float yPrecision;
+
+        int32_t pressureOrigin;
+        float pressureScale;
+
+        int32_t sizeOrigin;
+        float sizeScale;
+
+        float orientationScale;
+
+        // Oriented motion ranges for input device info.
+        struct OrientedRanges {
+            InputDeviceInfo::MotionRange x;
+            InputDeviceInfo::MotionRange y;
+            InputDeviceInfo::MotionRange pressure;
+            InputDeviceInfo::MotionRange size;
+            InputDeviceInfo::MotionRange touchMajor;
+            InputDeviceInfo::MotionRange touchMinor;
+            InputDeviceInfo::MotionRange toolMajor;
+            InputDeviceInfo::MotionRange toolMinor;
+            InputDeviceInfo::MotionRange orientation;
+        } orientedRanges;
+
+        // Oriented dimensions and precision.
+        float orientedSurfaceWidth, orientedSurfaceHeight;
+        float orientedXPrecision, orientedYPrecision;
+
+        struct CurrentVirtualKeyState {
+            bool down;
+            nsecs_t downTime;
+            int32_t keyCode;
+            int32_t scanCode;
+        } currentVirtualKey;
+    } mLocked;
 
     virtual void configureAxes();
-    virtual bool configureSurface();
-    virtual void configureVirtualKeys();
+    virtual bool configureSurfaceLocked();
+    virtual void configureVirtualKeysLocked();
 
     enum TouchResult {
         // Dispatch the touch normally.
@@ -696,15 +708,19 @@
         uint64_t distance : 48; // squared distance
     };
 
-    void initialize();
+    void initializeLocked();
 
     TouchResult consumeOffScreenTouches(nsecs_t when, uint32_t policyFlags);
     void dispatchTouches(nsecs_t when, uint32_t policyFlags);
     void dispatchTouch(nsecs_t when, uint32_t policyFlags, TouchData* touch,
             BitSet32 idBits, uint32_t changedId, int32_t motionEventAction);
 
-    bool isPointInsideSurface(int32_t x, int32_t y);
-    const VirtualKey* findVirtualKeyHitLvk(int32_t x, int32_t y);
+    void applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
+            int32_t keyEventAction, int32_t keyEventFlags,
+            int32_t keyCode, int32_t scanCode, nsecs_t downTime);
+
+    bool isPointInsideSurfaceLocked(int32_t x, int32_t y);
+    const VirtualKey* findVirtualKeyHitLocked(int32_t x, int32_t y);
 
     bool applyBadTouchFilter();
     bool applyJumpyTouchFilter();
diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp
index 0037399..7efc6d7 100644
--- a/libs/camera/Camera.cpp
+++ b/libs/camera/Camera.cpp
@@ -1,7 +1,6 @@
 /*
 **
 ** Copyright (C) 2008, The Android Open Source Project
-** Copyright (C) 2008 HTC Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 56e2977..6618702 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -713,15 +713,15 @@
         uint32_t sources, int32_t keyboardType) :
         InputMapper(device), mAssociatedDisplayId(associatedDisplayId), mSources(sources),
         mKeyboardType(keyboardType) {
-    initialize();
+    initializeLocked();
 }
 
 KeyboardInputMapper::~KeyboardInputMapper() {
 }
 
-void KeyboardInputMapper::initialize() {
-    mMetaState = AMETA_NONE;
-    mDownTime = 0;
+void KeyboardInputMapper::initializeLocked() {
+    mLocked.metaState = AMETA_NONE;
+    mLocked.downTime = 0;
 }
 
 uint32_t KeyboardInputMapper::getSources() {
@@ -735,17 +735,27 @@
 }
 
 void KeyboardInputMapper::reset() {
-    // Synthesize key up event on reset if keys are currently down.
-    while (! mKeyDowns.isEmpty()) {
-        const KeyDown& keyDown = mKeyDowns.top();
+    for (;;) {
+        int32_t keyCode, scanCode;
+        { // acquire lock
+            AutoMutex _l(mLock);
+
+            // Synthesize key up event on reset if keys are currently down.
+            if (mLocked.keyDowns.isEmpty()) {
+                initializeLocked();
+                break; // done
+            }
+
+            const KeyDown& keyDown = mLocked.keyDowns.top();
+            keyCode = keyDown.keyCode;
+            scanCode = keyDown.scanCode;
+        } // release lock
+
         nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
-        processKey(when, false, keyDown.keyCode, keyDown.scanCode, 0);
+        processKey(when, false, keyCode, scanCode, 0);
     }
 
     InputMapper::reset();
-
-    // Reinitialize.
-    initialize();
     getContext()->updateGlobalMetaState();
 }
 
@@ -768,56 +778,76 @@
         || (scanCode >= BTN_GAMEPAD && scanCode < BTN_DIGI);
 }
 
-void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
-        uint32_t policyFlags) {
-    if (down) {
-        // Rotate key codes according to orientation.
-        if (mAssociatedDisplayId >= 0) {
-            int32_t orientation;
-            if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
-                return;
+void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
+        int32_t scanCode, uint32_t policyFlags) {
+    int32_t newMetaState;
+    nsecs_t downTime;
+    bool metaStateChanged = false;
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        if (down) {
+            // Rotate key codes according to orientation if needed.
+            // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
+            if (mAssociatedDisplayId >= 0) {
+                int32_t orientation;
+                if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+                    return;
+                }
+
+                keyCode = rotateKeyCode(keyCode, orientation);
             }
 
-            keyCode = rotateKeyCode(keyCode, orientation);
+            // Add key down.
+            ssize_t keyDownIndex = findKeyDownLocked(scanCode);
+            if (keyDownIndex >= 0) {
+                // key repeat, be sure to use same keycode as before in case of rotation
+                keyCode = mLocked.keyDowns.top().keyCode;
+            } else {
+                // key down
+                mLocked.keyDowns.push();
+                KeyDown& keyDown = mLocked.keyDowns.editTop();
+                keyDown.keyCode = keyCode;
+                keyDown.scanCode = scanCode;
+            }
+
+            mLocked.downTime = when;
+        } else {
+            // Remove key down.
+            ssize_t keyDownIndex = findKeyDownLocked(scanCode);
+            if (keyDownIndex >= 0) {
+                // key up, be sure to use same keycode as before in case of rotation
+                keyCode = mLocked.keyDowns.top().keyCode;
+                mLocked.keyDowns.removeAt(size_t(keyDownIndex));
+            } else {
+                // key was not actually down
+                LOGI("Dropping key up from device %s because the key was not down.  "
+                        "keyCode=%d, scanCode=%d",
+                        getDeviceName().string(), keyCode, scanCode);
+                return;
+            }
         }
 
-        // Add key down.
-        ssize_t keyDownIndex = findKeyDown(scanCode);
-        if (keyDownIndex >= 0) {
-            // key repeat, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.top().keyCode;
-        } else {
-            // key down
-            mKeyDowns.push();
-            KeyDown& keyDown = mKeyDowns.editTop();
-            keyDown.keyCode = keyCode;
-            keyDown.scanCode = scanCode;
+        int32_t oldMetaState = mLocked.metaState;
+        newMetaState = updateMetaState(keyCode, down, oldMetaState);
+        if (oldMetaState != newMetaState) {
+            mLocked.metaState = newMetaState;
+            metaStateChanged = true;
         }
-    } else {
-        // Remove key down.
-        ssize_t keyDownIndex = findKeyDown(scanCode);
-        if (keyDownIndex >= 0) {
-            // key up, be sure to use same keycode as before in case of rotation
-            keyCode = mKeyDowns.top().keyCode;
-            mKeyDowns.removeAt(size_t(keyDownIndex));
-        } else {
-            // key was not actually down
-            LOGI("Dropping key up from device %s because the key was not down.  "
-                    "keyCode=%d, scanCode=%d",
-                    getDeviceName().string(), keyCode, scanCode);
-            return;
-        }
-    }
 
-    int32_t oldMetaState = mMetaState;
-    int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
-    if (oldMetaState != newMetaState) {
-        mMetaState = newMetaState;
+        downTime = mLocked.downTime;
+    } // release lock
+
+    if (metaStateChanged) {
         getContext()->updateGlobalMetaState();
     }
 
-    /* Apply policy. */
+    applyPolicyAndDispatch(when, policyFlags, down, keyCode, scanCode, newMetaState, downTime);
+}
 
+void KeyboardInputMapper::applyPolicyAndDispatch(nsecs_t when, uint32_t policyFlags, bool down,
+        int32_t keyCode, int32_t scanCode, int32_t metaState, nsecs_t downTime) {
     int32_t policyActions = getPolicy()->interceptKey(when,
             getDeviceId(), down, keyCode, scanCode, policyFlags);
 
@@ -825,30 +855,20 @@
         return; // event dropped
     }
 
-    /* Enqueue key event for dispatch. */
-
-    int32_t keyEventAction;
-    if (down) {
-        mDownTime = when;
-        keyEventAction = AKEY_EVENT_ACTION_DOWN;
-    } else {
-        keyEventAction = AKEY_EVENT_ACTION_UP;
-    }
-
+    int32_t keyEventAction = down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP;
     int32_t keyEventFlags = AKEY_EVENT_FLAG_FROM_SYSTEM;
     if (policyFlags & POLICY_FLAG_WOKE_HERE) {
         keyEventFlags = keyEventFlags | AKEY_EVENT_FLAG_WOKE_HERE;
     }
 
     getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
-            keyEventAction, keyEventFlags, keyCode, scanCode,
-            mMetaState, mDownTime);
+            keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
 }
 
-ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) {
-    size_t n = mKeyDowns.size();
+ssize_t KeyboardInputMapper::findKeyDownLocked(int32_t scanCode) {
+    size_t n = mLocked.keyDowns.size();
     for (size_t i = 0; i < n; i++) {
-        if (mKeyDowns[i].scanCode == scanCode) {
+        if (mLocked.keyDowns[i].scanCode == scanCode) {
             return i;
         }
     }
@@ -869,7 +889,10 @@
 }
 
 int32_t KeyboardInputMapper::getMetaState() {
-    return mMetaState;
+    { // acquire lock
+        AutoMutex _l(mLock);
+        return mLocked.metaState;
+    } // release lock
 }
 
 
@@ -882,7 +905,7 @@
     mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
     mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD;
 
-    initialize();
+    initializeLocked();
 }
 
 TrackballInputMapper::~TrackballInputMapper() {
@@ -899,26 +922,33 @@
     info->addMotionRange(AINPUT_MOTION_RANGE_Y, -1.0f, 1.0f, 0.0f, mYScale);
 }
 
-void TrackballInputMapper::initialize() {
+void TrackballInputMapper::initializeLocked() {
     mAccumulator.clear();
 
-    mDown = false;
-    mDownTime = 0;
+    mLocked.down = false;
+    mLocked.downTime = 0;
 }
 
 void TrackballInputMapper::reset() {
-    // Synthesize trackball button up event on reset if trackball button is currently down.
-    if (mDown) {
+    for (;;) {
+        { // acquire lock
+            AutoMutex _l(mLock);
+
+            if (! mLocked.down) {
+                initializeLocked();
+                break; // done
+            }
+        } // release lock
+
+        // Synthesize trackball button up event on reset.
         nsecs_t when = systemTime(SYSTEM_TIME_MONOTONIC);
-        mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
+        mAccumulator.fields = Accumulator::FIELD_BTN_MOUSE;
         mAccumulator.btnMouse = false;
         sync(when);
+        mAccumulator.clear();
     }
 
     InputMapper::reset();
-
-    // Reinitialize.
-    initialize();
 }
 
 void TrackballInputMapper::process(const RawEvent* rawEvent) {
@@ -962,33 +992,79 @@
 }
 
 void TrackballInputMapper::sync(nsecs_t when) {
-    /* Get display properties so for rotation based on display orientation. */
+    int motionEventAction;
+    PointerCoords pointerCoords;
+    nsecs_t downTime;
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-    int32_t orientation;
-    if (mAssociatedDisplayId >= 0) {
-        if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
-            return;
+        uint32_t fields = mAccumulator.fields;
+        bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
+
+        if (downChanged) {
+            if (mAccumulator.btnMouse) {
+                mLocked.down = true;
+                mLocked.downTime = when;
+            } else {
+                mLocked.down = false;
+            }
         }
-    } else {
-        orientation = InputReaderPolicyInterface::ROTATION_0;
-    }
 
-    /* Update saved trackball state */
+        downTime = mLocked.downTime;
+        float x = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX * mXScale : 0.0f;
+        float y = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY * mYScale : 0.0f;
 
-    uint32_t fields = mAccumulator.fields;
-    bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
-
-    if (downChanged) {
-        if (mAccumulator.btnMouse) {
-            mDown = true;
-            mDownTime = when;
+        if (downChanged) {
+            motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
         } else {
-            mDown = false;
+            motionEventAction = AMOTION_EVENT_ACTION_MOVE;
         }
-    }
 
-    /* Apply policy */
+        pointerCoords.x = x;
+        pointerCoords.y = y;
+        pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f;
+        pointerCoords.size = 0;
+        pointerCoords.touchMajor = 0;
+        pointerCoords.touchMinor = 0;
+        pointerCoords.toolMajor = 0;
+        pointerCoords.toolMinor = 0;
+        pointerCoords.orientation = 0;
 
+        if (mAssociatedDisplayId >= 0 && (x != 0.0f || y != 0.0f)) {
+            // Rotate motion based on display orientation if needed.
+            // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
+            int32_t orientation;
+            if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, NULL, NULL, & orientation)) {
+                return;
+            }
+
+            float temp;
+            switch (orientation) {
+            case InputReaderPolicyInterface::ROTATION_90:
+                temp = pointerCoords.x;
+                pointerCoords.x = pointerCoords.y;
+                pointerCoords.y = - temp;
+                break;
+
+            case InputReaderPolicyInterface::ROTATION_180:
+                pointerCoords.x = - pointerCoords.x;
+                pointerCoords.y = - pointerCoords.y;
+                break;
+
+            case InputReaderPolicyInterface::ROTATION_270:
+                temp = pointerCoords.x;
+                pointerCoords.x = - pointerCoords.y;
+                pointerCoords.y = temp;
+                break;
+            }
+        }
+    } // release lock
+
+    applyPolicyAndDispatch(when, motionEventAction, & pointerCoords, downTime);
+}
+
+void TrackballInputMapper::applyPolicyAndDispatch(nsecs_t when, int32_t motionEventAction,
+        PointerCoords* pointerCoords, nsecs_t downTime) {
     uint32_t policyFlags = 0;
     int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
 
@@ -996,62 +1072,24 @@
         return; // event dropped
     }
 
-    /* Enqueue motion event for dispatch. */
-
-    int32_t motionEventAction;
-    if (downChanged) {
-        motionEventAction = mDown ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
-    } else {
-        motionEventAction = AMOTION_EVENT_ACTION_MOVE;
-    }
-
-    int32_t pointerId = 0;
-    PointerCoords pointerCoords;
-    pointerCoords.x = fields & Accumulator::FIELD_REL_X
-            ? mAccumulator.relX * mXScale : 0;
-    pointerCoords.y = fields & Accumulator::FIELD_REL_Y
-            ? mAccumulator.relY * mYScale : 0;
-    pointerCoords.pressure = 1.0f; // XXX Consider making this 1.0f if down, 0 otherwise.
-    pointerCoords.size = 0;
-    pointerCoords.touchMajor = 0;
-    pointerCoords.touchMinor = 0;
-    pointerCoords.toolMajor = 0;
-    pointerCoords.toolMinor = 0;
-    pointerCoords.orientation = 0;
-
-    float temp;
-    switch (orientation) {
-    case InputReaderPolicyInterface::ROTATION_90:
-        temp = pointerCoords.x;
-        pointerCoords.x = pointerCoords.y;
-        pointerCoords.y = - temp;
-        break;
-
-    case InputReaderPolicyInterface::ROTATION_180:
-        pointerCoords.x = - pointerCoords.x;
-        pointerCoords.y = - pointerCoords.y;
-        break;
-
-    case InputReaderPolicyInterface::ROTATION_270:
-        temp = pointerCoords.x;
-        pointerCoords.x = - pointerCoords.y;
-        pointerCoords.y = temp;
-        break;
-    }
-
     int32_t metaState = mContext->getGlobalMetaState();
+    int32_t pointerId = 0;
+
     getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TRACKBALL, policyFlags,
             motionEventAction, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            1, & pointerId, & pointerCoords, mXPrecision, mYPrecision, mDownTime);
+            1, & pointerId, pointerCoords, mXPrecision, mYPrecision, downTime);
 }
 
 
 // --- TouchInputMapper ---
 
 TouchInputMapper::TouchInputMapper(InputDevice* device, int32_t associatedDisplayId) :
-        InputMapper(device), mAssociatedDisplayId(associatedDisplayId),
-        mSurfaceOrientation(-1), mSurfaceWidth(-1), mSurfaceHeight(-1) {
-    initialize();
+        InputMapper(device), mAssociatedDisplayId(associatedDisplayId) {
+    mLocked.surfaceOrientation = -1;
+    mLocked.surfaceWidth = -1;
+    mLocked.surfaceHeight = -1;
+
+    initializeLocked();
 }
 
 TouchInputMapper::~TouchInputMapper() {
@@ -1064,26 +1102,29 @@
 void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
     InputMapper::populateDeviceInfo(info);
 
-    // FIXME: Should ensure the surface information is up to date so that orientation changes
-    // are noticed immediately.  Unfortunately we will need to add some extra locks here
-    // to prevent race conditions.
-    // configureSurface();
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-    info->addMotionRange(AINPUT_MOTION_RANGE_X, mOrientedRanges.x);
-    info->addMotionRange(AINPUT_MOTION_RANGE_Y, mOrientedRanges.y);
-    info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mOrientedRanges.pressure);
-    info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mOrientedRanges.size);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mOrientedRanges.touchMajor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mOrientedRanges.touchMinor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mOrientedRanges.toolMajor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mOrientedRanges.toolMinor);
-    info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mOrientedRanges.orientation);
+        // Ensure surface information is up to date so that orientation changes are
+        // noticed immediately.
+        configureSurfaceLocked();
+
+        info->addMotionRange(AINPUT_MOTION_RANGE_X, mLocked.orientedRanges.x);
+        info->addMotionRange(AINPUT_MOTION_RANGE_Y, mLocked.orientedRanges.y);
+        info->addMotionRange(AINPUT_MOTION_RANGE_PRESSURE, mLocked.orientedRanges.pressure);
+        info->addMotionRange(AINPUT_MOTION_RANGE_SIZE, mLocked.orientedRanges.size);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MAJOR, mLocked.orientedRanges.touchMajor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOUCH_MINOR, mLocked.orientedRanges.touchMinor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MAJOR, mLocked.orientedRanges.toolMajor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_TOOL_MINOR, mLocked.orientedRanges.toolMinor);
+        info->addMotionRange(AINPUT_MOTION_RANGE_ORIENTATION, mLocked.orientedRanges.orientation);
+    } // release lock
 }
 
-void TouchInputMapper::initialize() {
+void TouchInputMapper::initializeLocked() {
+    mCurrentTouch.clear();
     mLastTouch.clear();
     mDownTime = 0;
-    mCurrentVirtualKey.down = false;
 
     for (uint32_t i = 0; i < MAX_POINTERS; i++) {
         mAveragingTouchFilter.historyStart[i] = 0;
@@ -1091,6 +1132,8 @@
     }
 
     mJumpyTouchFilter.jumpyPointsDropped = 0;
+
+    mLocked.currentVirtualKey.down = false;
 }
 
 void TouchInputMapper::configure() {
@@ -1104,48 +1147,52 @@
     // Configure absolute axis information.
     configureAxes();
 
-    // Configure pressure factors.
-    if (mAxes.pressure.valid) {
-        mPressureOrigin = mAxes.pressure.minValue;
-        mPressureScale = 1.0f / mAxes.pressure.getRange();
-    } else {
-        mPressureOrigin = 0;
-        mPressureScale = 1.0f;
-    }
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-    mOrientedRanges.pressure.min = 0.0f;
-    mOrientedRanges.pressure.max = 1.0f;
-    mOrientedRanges.pressure.flat = 0.0f;
-    mOrientedRanges.pressure.fuzz = mPressureScale;
+        // Configure pressure factors.
+        if (mAxes.pressure.valid) {
+            mLocked.pressureOrigin = mAxes.pressure.minValue;
+            mLocked.pressureScale = 1.0f / mAxes.pressure.getRange();
+        } else {
+            mLocked.pressureOrigin = 0;
+            mLocked.pressureScale = 1.0f;
+        }
 
-    // Configure size factors.
-    if (mAxes.size.valid) {
-        mSizeOrigin = mAxes.size.minValue;
-        mSizeScale = 1.0f / mAxes.size.getRange();
-    } else {
-        mSizeOrigin = 0;
-        mSizeScale = 1.0f;
-    }
+        mLocked.orientedRanges.pressure.min = 0.0f;
+        mLocked.orientedRanges.pressure.max = 1.0f;
+        mLocked.orientedRanges.pressure.flat = 0.0f;
+        mLocked.orientedRanges.pressure.fuzz = mLocked.pressureScale;
 
-    mOrientedRanges.size.min = 0.0f;
-    mOrientedRanges.size.max = 1.0f;
-    mOrientedRanges.size.flat = 0.0f;
-    mOrientedRanges.size.fuzz = mSizeScale;
+        // Configure size factors.
+        if (mAxes.size.valid) {
+            mLocked.sizeOrigin = mAxes.size.minValue;
+            mLocked.sizeScale = 1.0f / mAxes.size.getRange();
+        } else {
+            mLocked.sizeOrigin = 0;
+            mLocked.sizeScale = 1.0f;
+        }
 
-    // Configure orientation factors.
-    if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) {
-        mOrientationScale = float(M_PI_2) / mAxes.orientation.maxValue;
-    } else {
-        mOrientationScale = 0.0f;
-    }
+        mLocked.orientedRanges.size.min = 0.0f;
+        mLocked.orientedRanges.size.max = 1.0f;
+        mLocked.orientedRanges.size.flat = 0.0f;
+        mLocked.orientedRanges.size.fuzz = mLocked.sizeScale;
 
-    mOrientedRanges.orientation.min = - M_PI_2;
-    mOrientedRanges.orientation.max = M_PI_2;
-    mOrientedRanges.orientation.flat = 0;
-    mOrientedRanges.orientation.fuzz = mOrientationScale;
+        // Configure orientation factors.
+        if (mAxes.orientation.valid && mAxes.orientation.maxValue > 0) {
+            mLocked.orientationScale = float(M_PI_2) / mAxes.orientation.maxValue;
+        } else {
+            mLocked.orientationScale = 0.0f;
+        }
 
-    // Configure surface dimensions and orientation.
-    configureSurface();
+        mLocked.orientedRanges.orientation.min = - M_PI_2;
+        mLocked.orientedRanges.orientation.max = M_PI_2;
+        mLocked.orientedRanges.orientation.flat = 0;
+        mLocked.orientedRanges.orientation.fuzz = mLocked.orientationScale;
+
+        // Configure surface dimensions and orientation.
+        configureSurfaceLocked();
+    } // release lock
 }
 
 void TouchInputMapper::configureAxes() {
@@ -1160,11 +1207,12 @@
     mAxes.orientation.valid = false;
 }
 
-bool TouchInputMapper::configureSurface() {
+bool TouchInputMapper::configureSurfaceLocked() {
     // Update orientation and dimensions if needed.
     int32_t orientation;
     int32_t width, height;
     if (mAssociatedDisplayId >= 0) {
+        // Note: getDisplayInfo is non-reentrant so we can continue holding the lock.
         if (! getPolicy()->getDisplayInfo(mAssociatedDisplayId, & width, & height, & orientation)) {
             return false;
         }
@@ -1174,150 +1222,152 @@
         height = mAxes.y.getRange();
     }
 
-    bool orientationChanged = mSurfaceOrientation != orientation;
+    bool orientationChanged = mLocked.surfaceOrientation != orientation;
     if (orientationChanged) {
-        mSurfaceOrientation = orientation;
+        mLocked.surfaceOrientation = orientation;
     }
 
-    bool sizeChanged = mSurfaceWidth != width || mSurfaceHeight != height;
+    bool sizeChanged = mLocked.surfaceWidth != width || mLocked.surfaceHeight != height;
     if (sizeChanged) {
-        mSurfaceWidth = width;
-        mSurfaceHeight = height;
+        mLocked.surfaceWidth = width;
+        mLocked.surfaceHeight = height;
 
         // Compute size-dependent translation and scaling factors and place virtual keys.
         if (mAxes.x.valid && mAxes.y.valid) {
-            mXOrigin = mAxes.x.minValue;
-            mYOrigin = mAxes.y.minValue;
+            mLocked.xOrigin = mAxes.x.minValue;
+            mLocked.yOrigin = mAxes.y.minValue;
 
             LOGI("Device configured: id=0x%x, name=%s (display size was changed)",
                     getDeviceId(), getDeviceName().string());
 
-            mXScale = float(width) / mAxes.x.getRange();
-            mYScale = float(height) / mAxes.y.getRange();
-            mXPrecision = 1.0f / mXScale;
-            mYPrecision = 1.0f / mYScale;
+            mLocked.xScale = float(width) / mAxes.x.getRange();
+            mLocked.yScale = float(height) / mAxes.y.getRange();
+            mLocked.xPrecision = 1.0f / mLocked.xScale;
+            mLocked.yPrecision = 1.0f / mLocked.yScale;
 
-            configureVirtualKeys();
+            configureVirtualKeysLocked();
         } else {
-            mXOrigin = 0;
-            mYOrigin = 0;
-            mXScale = 1.0f;
-            mYScale = 1.0f;
-            mXPrecision = 1.0f;
-            mYPrecision = 1.0f;
+            mLocked.xOrigin = 0;
+            mLocked.yOrigin = 0;
+            mLocked.xScale = 1.0f;
+            mLocked.yScale = 1.0f;
+            mLocked.xPrecision = 1.0f;
+            mLocked.yPrecision = 1.0f;
         }
 
         // Configure touch and tool area ranges.
         float diagonal = sqrt(float(width * width + height * height));
-        float diagonalFuzz = sqrt(mXScale * mXScale + mYScale * mYScale);
+        float diagonalFuzz = sqrt(mLocked.xScale * mLocked.xScale
+                + mLocked.yScale * mLocked.yScale);
 
-        mOrientedRanges.touchMajor.min = 0.0f;
-        mOrientedRanges.touchMajor.max = diagonal;
-        mOrientedRanges.touchMajor.flat = 0.0f;
-        mOrientedRanges.touchMajor.fuzz = diagonalFuzz;
-        mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
+        InputDeviceInfo::MotionRange area;
+        area.min = 0.0f;
+        area.max = diagonal;
+        area.flat = 0.0f;
+        area.fuzz = diagonalFuzz;
 
-        mOrientedRanges.toolMinor = mOrientedRanges.toolMajor = mOrientedRanges.touchMajor;
+        mLocked.orientedRanges.touchMajor = area;
+        mLocked.orientedRanges.touchMinor = area;
+
+        mLocked.orientedRanges.toolMajor = area;
+        mLocked.orientedRanges.toolMinor = area;
     }
 
     if (orientationChanged || sizeChanged) {
         // Compute oriented surface dimensions, precision, and scales.
         float orientedXScale, orientedYScale;
-        switch (mSurfaceOrientation) {
+        switch (mLocked.surfaceOrientation) {
         case InputReaderPolicyInterface::ROTATION_90:
         case InputReaderPolicyInterface::ROTATION_270:
-            mOrientedSurfaceWidth = mSurfaceHeight;
-            mOrientedSurfaceHeight = mSurfaceWidth;
-            mOrientedXPrecision = mYPrecision;
-            mOrientedYPrecision = mXPrecision;
-            orientedXScale = mYScale;
-            orientedYScale = mXScale;
+            mLocked.orientedSurfaceWidth = mLocked.surfaceHeight;
+            mLocked.orientedSurfaceHeight = mLocked.surfaceWidth;
+            mLocked.orientedXPrecision = mLocked.yPrecision;
+            mLocked.orientedYPrecision = mLocked.xPrecision;
+            orientedXScale = mLocked.yScale;
+            orientedYScale = mLocked.xScale;
             break;
         default:
-            mOrientedSurfaceWidth = mSurfaceWidth;
-            mOrientedSurfaceHeight = mSurfaceHeight;
-            mOrientedXPrecision = mXPrecision;
-            mOrientedYPrecision = mYPrecision;
-            orientedXScale = mXScale;
-            orientedYScale = mYScale;
+            mLocked.orientedSurfaceWidth = mLocked.surfaceWidth;
+            mLocked.orientedSurfaceHeight = mLocked.surfaceHeight;
+            mLocked.orientedXPrecision = mLocked.xPrecision;
+            mLocked.orientedYPrecision = mLocked.yPrecision;
+            orientedXScale = mLocked.xScale;
+            orientedYScale = mLocked.yScale;
             break;
         }
 
         // Configure position ranges.
-        mOrientedRanges.x.min = 0;
-        mOrientedRanges.x.max = mOrientedSurfaceWidth;
-        mOrientedRanges.x.flat = 0;
-        mOrientedRanges.x.fuzz = orientedXScale;
+        mLocked.orientedRanges.x.min = 0;
+        mLocked.orientedRanges.x.max = mLocked.orientedSurfaceWidth;
+        mLocked.orientedRanges.x.flat = 0;
+        mLocked.orientedRanges.x.fuzz = orientedXScale;
 
-        mOrientedRanges.y.min = 0;
-        mOrientedRanges.y.max = mOrientedSurfaceHeight;
-        mOrientedRanges.y.flat = 0;
-        mOrientedRanges.y.fuzz = orientedYScale;
+        mLocked.orientedRanges.y.min = 0;
+        mLocked.orientedRanges.y.max = mLocked.orientedSurfaceHeight;
+        mLocked.orientedRanges.y.flat = 0;
+        mLocked.orientedRanges.y.fuzz = orientedYScale;
     }
 
     return true;
 }
 
-void TouchInputMapper::configureVirtualKeys() {
+void TouchInputMapper::configureVirtualKeysLocked() {
     assert(mAxes.x.valid && mAxes.y.valid);
 
+    // Note: getVirtualKeyDefinitions is non-reentrant so we can continue holding the lock.
     Vector<InputReaderPolicyInterface::VirtualKeyDefinition> virtualKeyDefinitions;
     getPolicy()->getVirtualKeyDefinitions(getDeviceName(), virtualKeyDefinitions);
 
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    mLocked.virtualKeys.clear();
 
-        mVirtualKeys.clear();
+    if (virtualKeyDefinitions.size() == 0) {
+        return;
+    }
 
-        if (virtualKeyDefinitions.size() == 0) {
-            return;
+    mLocked.virtualKeys.setCapacity(virtualKeyDefinitions.size());
+
+    int32_t touchScreenLeft = mAxes.x.minValue;
+    int32_t touchScreenTop = mAxes.y.minValue;
+    int32_t touchScreenWidth = mAxes.x.getRange();
+    int32_t touchScreenHeight = mAxes.y.getRange();
+
+    for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
+        const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
+                virtualKeyDefinitions[i];
+
+        mLocked.virtualKeys.add();
+        VirtualKey& virtualKey = mLocked.virtualKeys.editTop();
+
+        virtualKey.scanCode = virtualKeyDefinition.scanCode;
+        int32_t keyCode;
+        uint32_t flags;
+        if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
+                & keyCode, & flags)) {
+            LOGW("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
+            mLocked.virtualKeys.pop(); // drop the key
+            continue;
         }
 
-        mVirtualKeys.setCapacity(virtualKeyDefinitions.size());
+        virtualKey.keyCode = keyCode;
+        virtualKey.flags = flags;
 
-        int32_t touchScreenLeft = mAxes.x.minValue;
-        int32_t touchScreenTop = mAxes.y.minValue;
-        int32_t touchScreenWidth = mAxes.x.getRange();
-        int32_t touchScreenHeight = mAxes.y.getRange();
+        // convert the key definition's display coordinates into touch coordinates for a hit box
+        int32_t halfWidth = virtualKeyDefinition.width / 2;
+        int32_t halfHeight = virtualKeyDefinition.height / 2;
 
-        for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
-            const InputReaderPolicyInterface::VirtualKeyDefinition& virtualKeyDefinition =
-                    virtualKeyDefinitions[i];
+        virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
+                * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;
+        virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
+                * touchScreenWidth / mLocked.surfaceWidth + touchScreenLeft;
+        virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
+                * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
+        virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
+                * touchScreenHeight / mLocked.surfaceHeight + touchScreenTop;
 
-            mVirtualKeys.add();
-            VirtualKey& virtualKey = mVirtualKeys.editTop();
-
-            virtualKey.scanCode = virtualKeyDefinition.scanCode;
-            int32_t keyCode;
-            uint32_t flags;
-            if (getEventHub()->scancodeToKeycode(getDeviceId(), virtualKey.scanCode,
-                    & keyCode, & flags)) {
-                LOGW("  VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
-                mVirtualKeys.pop(); // drop the key
-                continue;
-            }
-
-            virtualKey.keyCode = keyCode;
-            virtualKey.flags = flags;
-
-            // convert the key definition's display coordinates into touch coordinates for a hit box
-            int32_t halfWidth = virtualKeyDefinition.width / 2;
-            int32_t halfHeight = virtualKeyDefinition.height / 2;
-
-            virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth)
-                    * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
-            virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth)
-                    * touchScreenWidth / mSurfaceWidth + touchScreenLeft;
-            virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight)
-                    * touchScreenHeight / mSurfaceHeight + touchScreenTop;
-            virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight)
-                    * touchScreenHeight / mSurfaceHeight + touchScreenTop;
-
-            LOGI("  VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
-                    virtualKey.scanCode, virtualKey.keyCode,
-                    virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
-        }
-    } // release virtual key lock
+        LOGI("  VirtualKey %d: keyCode=%d hitLeft=%d hitRight=%d hitTop=%d hitBottom=%d",
+                virtualKey.scanCode, virtualKey.keyCode,
+                virtualKey.hitLeft, virtualKey.hitRight, virtualKey.hitTop, virtualKey.hitBottom);
+    }
 }
 
 void TouchInputMapper::reset() {
@@ -1329,20 +1379,16 @@
         syncTouch(when, true);
     }
 
-    InputMapper::reset();
+    { // acquire lock
+        AutoMutex _l(mLock);
+        initializeLocked();
+    } // release lock
 
-    // Reinitialize.
-    initialize();
+    InputMapper::reset();
 }
 
 void TouchInputMapper::syncTouch(nsecs_t when, bool havePointerIds) {
-    /* Refresh associated display information and update our size configuration if needed. */
-
-    if (! configureSurface()) {
-        return;
-    }
-
-    /* Apply policy */
+    // Apply generic policy actions.
 
     uint32_t policyFlags = 0;
     int32_t policyActions = getPolicy()->interceptGeneric(when, policyFlags);
@@ -1352,7 +1398,7 @@
         return; // event dropped
     }
 
-    /* Preprocess pointer data */
+    // Preprocess pointer data.
 
     if (mParameters.useBadTouchFilter) {
         if (applyBadTouchFilter()) {
@@ -1381,14 +1427,14 @@
         savedTouch = & mCurrentTouch;
     }
 
-    /* Process touches and virtual keys */
+    // Process touches and virtual keys.
 
     TouchResult touchResult = consumeOffScreenTouches(when, policyFlags);
     if (touchResult == DISPATCH_TOUCH) {
         dispatchTouches(when, policyFlags);
     }
 
-    /* Copy current touch to last touch in preparation for the next cycle. */
+    // Copy current touch to last touch in preparation for the next cycle.
 
     if (touchResult == DROP_STROKE) {
         mLastTouch.clear();
@@ -1403,13 +1449,19 @@
     int32_t keyCode, scanCode, downTime;
     TouchResult touchResult;
 
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        if (mCurrentVirtualKey.down) {
+        // Update surface size and orientation, including virtual key positions.
+        if (! configureSurfaceLocked()) {
+            return DROP_STROKE;
+        }
+
+        // Check for virtual key press.
+        if (mLocked.currentVirtualKey.down) {
             if (mCurrentTouch.pointerCount == 0) {
                 // Pointer went up while virtual key was down.
-                mCurrentVirtualKey.down = false;
+                mLocked.currentVirtualKey.down = false;
 #if DEBUG_VIRTUAL_KEYS
                 LOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d",
                         mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
@@ -1423,8 +1475,8 @@
             if (mCurrentTouch.pointerCount == 1) {
                 int32_t x = mCurrentTouch.pointers[0].x;
                 int32_t y = mCurrentTouch.pointers[0].y;
-                const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
-                if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) {
+                const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y);
+                if (virtualKey && virtualKey->keyCode == mLocked.currentVirtualKey.keyCode) {
                     // Pointer is still within the space of the virtual key.
                     return SKIP_TOUCH;
                 }
@@ -1434,7 +1486,7 @@
             // Send key cancellation and drop the stroke so subsequent motions will be
             // considered fresh downs.  This is useful when the user swipes away from the
             // virtual key area into the main display surface.
-            mCurrentVirtualKey.down = false;
+            mLocked.currentVirtualKey.down = false;
 #if DEBUG_VIRTUAL_KEYS
             LOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d",
                     mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
@@ -1449,16 +1501,16 @@
                 // Pointer just went down.  Handle off-screen touches, if needed.
                 int32_t x = mCurrentTouch.pointers[0].x;
                 int32_t y = mCurrentTouch.pointers[0].y;
-                if (! isPointInsideSurface(x, y)) {
+                if (! isPointInsideSurfaceLocked(x, y)) {
                     // If exactly one pointer went down, check for virtual key hit.
                     // Otherwise we will drop the entire stroke.
                     if (mCurrentTouch.pointerCount == 1) {
-                        const VirtualKey* virtualKey = findVirtualKeyHitLvk(x, y);
+                        const VirtualKey* virtualKey = findVirtualKeyHitLocked(x, y);
                         if (virtualKey) {
-                            mCurrentVirtualKey.down = true;
-                            mCurrentVirtualKey.downTime = when;
-                            mCurrentVirtualKey.keyCode = virtualKey->keyCode;
-                            mCurrentVirtualKey.scanCode = virtualKey->scanCode;
+                            mLocked.currentVirtualKey.down = true;
+                            mLocked.currentVirtualKey.downTime = when;
+                            mLocked.currentVirtualKey.keyCode = virtualKey->keyCode;
+                            mLocked.currentVirtualKey.scanCode = virtualKey->scanCode;
 #if DEBUG_VIRTUAL_KEYS
                             LOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d",
                                     mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode);
@@ -1478,12 +1530,20 @@
 
     DispatchVirtualKey:
         // Collect remaining state needed to dispatch virtual key.
-        keyCode = mCurrentVirtualKey.keyCode;
-        scanCode = mCurrentVirtualKey.scanCode;
-        downTime = mCurrentVirtualKey.downTime;
-    } // release virtual key lock
+        keyCode = mLocked.currentVirtualKey.keyCode;
+        scanCode = mLocked.currentVirtualKey.scanCode;
+        downTime = mLocked.currentVirtualKey.downTime;
+    } // release lock
 
     // Dispatch virtual key.
+    applyPolicyAndDispatchVirtualKey(when, policyFlags, keyEventAction, keyEventFlags,
+            keyCode, scanCode, downTime);
+    return touchResult;
+}
+
+void TouchInputMapper::applyPolicyAndDispatchVirtualKey(nsecs_t when, uint32_t policyFlags,
+        int32_t keyEventAction, int32_t keyEventFlags,
+        int32_t keyCode, int32_t scanCode, nsecs_t downTime) {
     int32_t metaState = mContext->getGlobalMetaState();
 
     if (keyEventAction == AKEY_EVENT_ACTION_DOWN) {
@@ -1497,7 +1557,6 @@
         getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
                 keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
     }
-    return touchResult;
 }
 
 void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) {
@@ -1566,107 +1625,118 @@
     uint32_t pointerCount = 0;
     int32_t pointerIds[MAX_POINTERS];
     PointerCoords pointerCoords[MAX_POINTERS];
-
-    // Walk through the the active pointers and map touch screen coordinates (TouchData) into
-    // display coordinates (PointerCoords) and adjust for display orientation.
-    while (! idBits.isEmpty()) {
-        uint32_t id = idBits.firstMarkedBit();
-        idBits.clearBit(id);
-        uint32_t index = touch->idToIndex[id];
-
-        float x = float(touch->pointers[index].x - mXOrigin) * mXScale;
-        float y = float(touch->pointers[index].y - mYOrigin) * mYScale;
-        float pressure = float(touch->pointers[index].pressure - mPressureOrigin) * mPressureScale;
-        float size = float(touch->pointers[index].size - mSizeOrigin) * mSizeScale;
-
-        float orientation = float(touch->pointers[index].orientation) * mOrientationScale;
-
-        float touchMajor, touchMinor, toolMajor, toolMinor;
-        if (abs(orientation) <= M_PI_4) {
-            // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X.
-            touchMajor = float(touch->pointers[index].touchMajor) * mYScale;
-            touchMinor = float(touch->pointers[index].touchMinor) * mXScale;
-            toolMajor = float(touch->pointers[index].toolMajor) * mYScale;
-            toolMinor = float(touch->pointers[index].toolMinor) * mXScale;
-        } else {
-            // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y.
-            touchMajor = float(touch->pointers[index].touchMajor) * mXScale;
-            touchMinor = float(touch->pointers[index].touchMinor) * mYScale;
-            toolMajor = float(touch->pointers[index].toolMajor) * mXScale;
-            toolMinor = float(touch->pointers[index].toolMinor) * mYScale;
-        }
-
-        switch (mSurfaceOrientation) {
-        case InputReaderPolicyInterface::ROTATION_90: {
-            float xTemp = x;
-            x = y;
-            y = mSurfaceWidth - xTemp;
-            orientation -= M_PI_2;
-            if (orientation < - M_PI_2) {
-                orientation += M_PI;
-            }
-            break;
-        }
-        case InputReaderPolicyInterface::ROTATION_180: {
-            x = mSurfaceWidth - x;
-            y = mSurfaceHeight - y;
-            orientation = - orientation;
-            break;
-        }
-        case InputReaderPolicyInterface::ROTATION_270: {
-            float xTemp = x;
-            x = mSurfaceHeight - y;
-            y = xTemp;
-            orientation += M_PI_2;
-            if (orientation > M_PI_2) {
-                orientation -= M_PI;
-            }
-            break;
-        }
-        }
-
-        pointerIds[pointerCount] = int32_t(id);
-
-        pointerCoords[pointerCount].x = x;
-        pointerCoords[pointerCount].y = y;
-        pointerCoords[pointerCount].pressure = pressure;
-        pointerCoords[pointerCount].size = size;
-        pointerCoords[pointerCount].touchMajor = touchMajor;
-        pointerCoords[pointerCount].touchMinor = touchMinor;
-        pointerCoords[pointerCount].toolMajor = toolMajor;
-        pointerCoords[pointerCount].toolMinor = toolMinor;
-        pointerCoords[pointerCount].orientation = orientation;
-
-        if (id == changedId) {
-            motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
-        }
-
-        pointerCount += 1;
-    }
-
-    // Check edge flags by looking only at the first pointer since the flags are
-    // global to the event.
     int32_t motionEventEdgeFlags = 0;
-    if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
-        if (pointerCoords[0].x <= 0) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
-        } else if (pointerCoords[0].x >= mOrientedSurfaceWidth) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+    float xPrecision, yPrecision;
+
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        // Walk through the the active pointers and map touch screen coordinates (TouchData) into
+        // display coordinates (PointerCoords) and adjust for display orientation.
+        while (! idBits.isEmpty()) {
+            uint32_t id = idBits.firstMarkedBit();
+            idBits.clearBit(id);
+            uint32_t index = touch->idToIndex[id];
+
+            float x = float(touch->pointers[index].x - mLocked.xOrigin) * mLocked.xScale;
+            float y = float(touch->pointers[index].y - mLocked.yOrigin) * mLocked.yScale;
+            float pressure = float(touch->pointers[index].pressure - mLocked.pressureOrigin)
+                    * mLocked.pressureScale;
+            float size = float(touch->pointers[index].size - mLocked.sizeOrigin)
+                    * mLocked.sizeScale;
+
+            float orientation = float(touch->pointers[index].orientation)
+                    * mLocked.orientationScale;
+
+            float touchMajor, touchMinor, toolMajor, toolMinor;
+            if (abs(orientation) <= M_PI_4) {
+                // Nominally vertical orientation: scale major axis by Y, and scale minor axis by X.
+                touchMajor = float(touch->pointers[index].touchMajor) * mLocked.yScale;
+                touchMinor = float(touch->pointers[index].touchMinor) * mLocked.xScale;
+                toolMajor = float(touch->pointers[index].toolMajor) * mLocked.yScale;
+                toolMinor = float(touch->pointers[index].toolMinor) * mLocked.xScale;
+            } else {
+                // Nominally horizontal orientation: scale major axis by X, and scale minor axis by Y.
+                touchMajor = float(touch->pointers[index].touchMajor) * mLocked.xScale;
+                touchMinor = float(touch->pointers[index].touchMinor) * mLocked.yScale;
+                toolMajor = float(touch->pointers[index].toolMajor) * mLocked.xScale;
+                toolMinor = float(touch->pointers[index].toolMinor) * mLocked.yScale;
+            }
+
+            switch (mLocked.surfaceOrientation) {
+            case InputReaderPolicyInterface::ROTATION_90: {
+                float xTemp = x;
+                x = y;
+                y = mLocked.surfaceWidth - xTemp;
+                orientation -= M_PI_2;
+                if (orientation < - M_PI_2) {
+                    orientation += M_PI;
+                }
+                break;
+            }
+            case InputReaderPolicyInterface::ROTATION_180: {
+                x = mLocked.surfaceWidth - x;
+                y = mLocked.surfaceHeight - y;
+                orientation = - orientation;
+                break;
+            }
+            case InputReaderPolicyInterface::ROTATION_270: {
+                float xTemp = x;
+                x = mLocked.surfaceHeight - y;
+                y = xTemp;
+                orientation += M_PI_2;
+                if (orientation > M_PI_2) {
+                    orientation -= M_PI;
+                }
+                break;
+            }
+            }
+
+            pointerIds[pointerCount] = int32_t(id);
+
+            pointerCoords[pointerCount].x = x;
+            pointerCoords[pointerCount].y = y;
+            pointerCoords[pointerCount].pressure = pressure;
+            pointerCoords[pointerCount].size = size;
+            pointerCoords[pointerCount].touchMajor = touchMajor;
+            pointerCoords[pointerCount].touchMinor = touchMinor;
+            pointerCoords[pointerCount].toolMajor = toolMajor;
+            pointerCoords[pointerCount].toolMinor = toolMinor;
+            pointerCoords[pointerCount].orientation = orientation;
+
+            if (id == changedId) {
+                motionEventAction |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
+            }
+
+            pointerCount += 1;
         }
-        if (pointerCoords[0].y <= 0) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
-        } else if (pointerCoords[0].y >= mOrientedSurfaceHeight) {
-            motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+
+        // Check edge flags by looking only at the first pointer since the flags are
+        // global to the event.
+        if (motionEventAction == AMOTION_EVENT_ACTION_DOWN) {
+            if (pointerCoords[0].x <= 0) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_LEFT;
+            } else if (pointerCoords[0].x >= mLocked.orientedSurfaceWidth) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_RIGHT;
+            }
+            if (pointerCoords[0].y <= 0) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_TOP;
+            } else if (pointerCoords[0].y >= mLocked.orientedSurfaceHeight) {
+                motionEventEdgeFlags |= AMOTION_EVENT_EDGE_FLAG_BOTTOM;
+            }
         }
-    }
+
+        xPrecision = mLocked.orientedXPrecision;
+        yPrecision = mLocked.orientedYPrecision;
+    } // release lock
 
     getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_TOUCHSCREEN, policyFlags,
             motionEventAction, getContext()->getGlobalMetaState(), motionEventEdgeFlags,
             pointerCount, pointerIds, pointerCoords,
-            mOrientedXPrecision, mOrientedYPrecision, mDownTime);
+            xPrecision, yPrecision, mDownTime);
 }
 
-bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
+bool TouchInputMapper::isPointInsideSurfaceLocked(int32_t x, int32_t y) {
     if (mAxes.x.valid && mAxes.y.valid) {
         return x >= mAxes.x.minValue && x <= mAxes.x.maxValue
                 && y >= mAxes.y.minValue && y <= mAxes.y.maxValue;
@@ -1674,9 +1744,11 @@
     return true;
 }
 
-const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLvk(int32_t x, int32_t y) {
-    for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-        const VirtualKey& virtualKey = mVirtualKeys[i];
+const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHitLocked(
+        int32_t x, int32_t y) {
+    size_t numVirtualKeys = mLocked.virtualKeys.size();
+    for (size_t i = 0; i < numVirtualKeys; i++) {
+        const VirtualKey& virtualKey = mLocked.virtualKeys[i];
 
 #if DEBUG_VIRTUAL_KEYS
         LOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, "
@@ -2224,50 +2296,53 @@
 }
 
 int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) {
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) {
+        if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.keyCode == keyCode) {
             return AKEY_STATE_VIRTUAL;
         }
 
-        for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys[i];
+        size_t numVirtualKeys = mLocked.virtualKeys.size();
+        for (size_t i = 0; i < numVirtualKeys; i++) {
+            const VirtualKey& virtualKey = mLocked.virtualKeys[i];
             if (virtualKey.keyCode == keyCode) {
                 return AKEY_STATE_UP;
             }
         }
-    } // release virtual key lock
+    } // release lock
 
     return AKEY_STATE_UNKNOWN;
 }
 
 int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) {
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) {
+        if (mLocked.currentVirtualKey.down && mLocked.currentVirtualKey.scanCode == scanCode) {
             return AKEY_STATE_VIRTUAL;
         }
 
-        for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys[i];
+        size_t numVirtualKeys = mLocked.virtualKeys.size();
+        for (size_t i = 0; i < numVirtualKeys; i++) {
+            const VirtualKey& virtualKey = mLocked.virtualKeys[i];
             if (virtualKey.scanCode == scanCode) {
                 return AKEY_STATE_UP;
             }
         }
-    } // release virtual key lock
+    } // release lock
 
     return AKEY_STATE_UNKNOWN;
 }
 
 bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
         const int32_t* keyCodes, uint8_t* outFlags) {
-    { // acquire virtual key lock
-        AutoMutex _l(mVirtualKeyLock);
+    { // acquire lock
+        AutoMutex _l(mLock);
 
-        for (size_t i = 0; i < mVirtualKeys.size(); i++) {
-            const VirtualKey& virtualKey = mVirtualKeys[i];
+        size_t numVirtualKeys = mLocked.virtualKeys.size();
+        for (size_t i = 0; i < numVirtualKeys; i++) {
+            const VirtualKey& virtualKey = mLocked.virtualKeys[i];
 
             for (size_t i = 0; i < numCodes; i++) {
                 if (virtualKey.keyCode == keyCodes[i]) {
@@ -2275,7 +2350,7 @@
                 }
             }
         }
-    } // release virtual key lock
+    } // release lock
 
     return true;
 }
@@ -2304,7 +2379,6 @@
 void SingleTouchInputMapper::reset() {
     TouchInputMapper::reset();
 
-    // Reinitialize.
     initialize();
  }
 
@@ -2436,7 +2510,6 @@
 void MultiTouchInputMapper::reset() {
     TouchInputMapper::reset();
 
-    // Reinitialize.
     initialize();
 }
 
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index 9fe207c..4eb63e8 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, The Android Open Source Project
  **
  ** Licensed under the Apache License, Version 2.0 (the "License");
  ** you may not use this file except in compliance with the License.
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index fef3e6e..73862c3 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -1,5 +1,5 @@
 /*
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, The Android Open Source Project
  **
  ** Licensed under the Apache License, Version 2.0 (the "License");
  ** you may not use this file except in compliance with the License.
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index d12e558..1d1913d 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -1,6 +1,6 @@
 /*
  **
- ** Copyright 2008, HTC Inc.
+ ** Copyright 2008, The Android Open Source Project
  **
  ** Licensed under the Apache License, Version 2.0 (the "License");
  ** you may not use this file except in compliance with the License.
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f26676d..c40d285 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -344,7 +344,7 @@
 
 status_t StagefrightRecorder::setParamMaxFileDurationUs(int64_t timeUs) {
     LOGV("setParamMaxFileDurationUs: %lld us", timeUs);
-    if (timeUs <= 1000000LL) {  // XXX: 1 second
+    if (timeUs <= 100000LL) {  // XXX: 100 milli-seconds
         LOGE("Max file duration is too short: %lld us", timeUs);
         return BAD_VALUE;
     }
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index baf9f4f..9f712c3 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -1615,6 +1615,16 @@
                         mOwner->write(kData2, sizeof(kData2));
 
                     mOwner->endBox();  // esds
+                  } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime) ||
+                             !strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+                    // 3gpp2 Spec AMRSampleEntry fields
+                    mOwner->beginBox("damr");
+                      mOwner->writeCString("   ");  // vendor: 4 bytes
+                      mOwner->writeInt8(0);         // decoder version
+                      mOwner->writeInt16(0x83FF);   // mode set: all enabled
+                      mOwner->writeInt8(0);         // mode change period
+                      mOwner->writeInt8(1);         // frames per sample
+                    mOwner->endBox();
                   }
                 mOwner->endBox();
             } else {
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c786f94..3b3904a 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -1,7 +1,6 @@
 /*
 **
 ** Copyright (C) 2008, The Android Open Source Project
-** Copyright (C) 2008 HTC Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index b0b2d7a..77ccf41 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -1,7 +1,6 @@
 /*
 **
 ** Copyright (C) 2008, The Android Open Source Project
-** Copyright (C) 2008 HTC Inc.
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index bcbda3e..162fffe 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6101,17 +6101,19 @@
     }
 
     public void handleApplicationStrictModeViolation(
-        IBinder app, int violationMask, ApplicationErrorReport.CrashInfo crashInfo) {
+            IBinder app,
+            int violationMask,
+            StrictMode.ViolationInfo info) {
         ProcessRecord r = findAppProcess(app);
 
         if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
-            Integer stackFingerprint = crashInfo.stackTrace.hashCode();
+            Integer stackFingerprint = info.crashInfo.stackTrace.hashCode();
             boolean logIt = true;
             synchronized (mAlreadyLoggedViolatedStacks) {
                 if (mAlreadyLoggedViolatedStacks.contains(stackFingerprint)) {
                     logIt = false;
                     // TODO: sub-sample into EventLog for these, with
-                    // the crashInfo.durationMillis?  Then we'd get
+                    // the info.durationMillis?  Then we'd get
                     // the relative pain numbers, without logging all
                     // the stack traces repeatedly.  We'd want to do
                     // likewise in the client code, which also does
@@ -6124,7 +6126,7 @@
                 }
             }
             if (logIt) {
-                logStrictModeViolationToDropBox(r, crashInfo);
+                logStrictModeViolationToDropBox(r, info);
             }
         }
 
@@ -6139,7 +6141,7 @@
                 data.put("result", result);
                 data.put("app", r);
                 data.put("violationMask", violationMask);
-                data.put("crashInfo", crashInfo);
+                data.put("info", info);
                 msg.obj = data;
                 mHandler.sendMessage(msg);
 
@@ -6154,9 +6156,10 @@
     // these in quick succession so we try to batch these together to
     // minimize disk writes, number of dropbox entries, and maximize
     // compression, by having more fewer, larger records.
-    private void logStrictModeViolationToDropBox(ProcessRecord process,
-                                                 ApplicationErrorReport.CrashInfo crashInfo) {
-        if (crashInfo == null) {
+    private void logStrictModeViolationToDropBox(
+            ProcessRecord process,
+            StrictMode.ViolationInfo info) {
+        if (info == null) {
             return;
         }
         final boolean isSystemApp = process == null ||
@@ -6177,12 +6180,16 @@
             appendDropBoxProcessHeaders(process, sb);
             sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
             sb.append("System-App: ").append(isSystemApp).append("\n");
-            if (crashInfo != null && crashInfo.durationMillis != -1) {
-                sb.append("Duration-Millis: ").append(crashInfo.durationMillis).append("\n");
+            sb.append("Uptime-Millis: ").append(info.violationUptimeMillis).append("\n");
+            if (info.violationNumThisLoop != 0) {
+                sb.append("Loop-Violation-Number: ").append(info.violationNumThisLoop).append("\n");
+            }
+            if (info != null && info.durationMillis != -1) {
+                sb.append("Duration-Millis: ").append(info.durationMillis).append("\n");
             }
             sb.append("\n");
-            if (crashInfo != null && crashInfo.stackTrace != null) {
-                sb.append(crashInfo.stackTrace);
+            if (info.crashInfo != null && info.crashInfo.stackTrace != null) {
+                sb.append(info.crashInfo.stackTrace);
             }
             sb.append("\n");