Merge "- Consolidate all animations in a single place outside of layout loop. - Move mPolicy.startAnimationLw and mPolicy.finishAnimationLw into same method as mPolicy.animatingWindowLw. - Fix first parameter of performLayoutLockedInner(initial, ...) to pass true on initial pass."
diff --git a/api/current.txt b/api/current.txt
index 8c0dc14..d034b89 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -23310,6 +23310,9 @@
     method protected void onMeasure(int, int);
     method protected void onOverScrolled(int, int, boolean, boolean);
     method public void onPopulateAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
+    method public void onResetResolvedTextDirection();
+    method public void onResolvePadding(int);
+    method public void onResolveTextDirection();
     method protected void onRestoreInstanceState(android.os.Parcelable);
     method protected android.os.Parcelable onSaveInstanceState();
     method protected void onScrollChanged(int, int, int, int);
@@ -23344,10 +23347,11 @@
     method public void requestLayout();
     method public boolean requestRectangleOnScreen(android.graphics.Rect);
     method public boolean requestRectangleOnScreen(android.graphics.Rect, boolean);
-    method protected void resetResolvedTextDirection();
+    method public void resetResolvedTextDirection();
+    method public void resolvePadding();
     method public static int resolveSize(int, int);
     method public static int resolveSizeAndState(int, int, int);
-    method protected void resolveTextDirection();
+    method public void resolveTextDirection();
     method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void scheduleDrawable(android.graphics.drawable.Drawable, java.lang.Runnable, long);
diff --git a/cmds/backup/Android.mk b/cmds/backup/Android.mk
index 508aec0..73af0bc 100644
--- a/cmds/backup/Android.mk
+++ b/cmds/backup/Android.mk
@@ -5,7 +5,7 @@
 
 LOCAL_SRC_FILES:= backup.cpp
 
-LOCAL_SHARED_LIBRARIES := libcutils libutils
+LOCAL_SHARED_LIBRARIES := libcutils libutils libandroidfw
 
 LOCAL_MODULE:= btool
 
diff --git a/cmds/backup/backup.cpp b/cmds/backup/backup.cpp
index d4e669b..ea1888b 100644
--- a/cmds/backup/backup.cpp
+++ b/cmds/backup/backup.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 #include <utils/String8.h>
 
 #include <fcntl.h>
diff --git a/cmds/bootanimation/Android.mk b/cmds/bootanimation/Android.mk
index 7d39912..8c46b21 100644
--- a/cmds/bootanimation/Android.mk
+++ b/cmds/bootanimation/Android.mk
@@ -9,6 +9,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
 	libcutils \
+	libandroidfw \
 	libutils \
 	libbinder \
     libui \
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 0d5b4ca..3545ace 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -25,12 +25,12 @@
 
 #include <cutils/properties.h>
 
+#include <androidfw/AssetManager.h>
 #include <binder/IPCThreadState.h>
-#include <utils/threads.h>
 #include <utils/Atomic.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
-#include <utils/AssetManager.h>
+#include <utils/threads.h>
 
 #include <ui/PixelFormat.h>
 #include <ui/Rect.h>
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 8e28bba..c85d72c 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -20,8 +20,8 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <androidfw/AssetManager.h>
 #include <utils/threads.h>
-#include <utils/AssetManager.h>
 
 #include <surfaceflinger/ISurfaceComposer.h>
 #include <surfaceflinger/SurfaceComposerClient.h>
diff --git a/cmds/content/Android.mk b/cmds/content/Android.mk
new file mode 100644
index 0000000..a3d83cf
--- /dev/null
+++ b/cmds/content/Android.mk
@@ -0,0 +1,35 @@
+# Copyright 2012 The Android Open Source Project
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE := content
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+ALL_PREBUILT += $(TARGET_OUT)/bin/content
+$(TARGET_OUT)/bin/content : $(LOCAL_PATH)/content | $(ACP)
+	$(transform-prebuilt-to-target)
+
+NOTICE_FILE := NOTICE
+files_noticed := bin/content
+
+# Generate rules for a single file. The argument is the file path relative to
+# the installation root
+define make-notice-file
+
+$(TARGET_OUT_NOTICE_FILES)/src/$(1).txt: $(LOCAL_PATH)/$(NOTICE_FILE)
+	@echo Notice file: $$< -- $$@
+	@mkdir -p $$(dir $$@)
+	@cat $$< >> $$@
+
+$(TARGET_OUT_NOTICE_FILES)/hash-timestamp: $(TARGET_OUT_NOTICE_FILES)/src/$(1).txt
+
+endef
+
+$(foreach file,$(files_noticed),$(eval $(call make-notice-file,$(file))))
diff --git a/cmds/content/MODULE_LICENSE_APACHE2 b/cmds/content/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/content/MODULE_LICENSE_APACHE2
diff --git a/cmds/content/NOTICE b/cmds/content/NOTICE
new file mode 100644
index 0000000..33ff961
--- /dev/null
+++ b/cmds/content/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-2012, 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.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/cmds/content/content b/cmds/content/content
new file mode 100755
index 0000000..a8e056d
--- /dev/null
+++ b/cmds/content/content
@@ -0,0 +1,5 @@
+# Script to start "content" on the device, which has a very rudimentary shell.
+base=/system
+export CLASSPATH=$base/framework/content.jar
+exec app_process $base/bin com.android.commands.content.Content "$@"
+
diff --git a/cmds/content/src/com/android/commands/content/Content.java b/cmds/content/src/com/android/commands/content/Content.java
new file mode 100644
index 0000000..1dcba70
--- /dev/null
+++ b/cmds/content/src/com/android/commands/content/Content.java
@@ -0,0 +1,442 @@
+/*
+** Copyright 2012, 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.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.commands.content;
+
+import android.app.ActivityManagerNative;
+import android.app.IActivityManager;
+import android.app.IActivityManager.ContentProviderHolder;
+import android.content.ContentValues;
+import android.content.IContentProvider;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.IBinder;
+import android.text.TextUtils;
+
+/**
+ * This class is a command line utility for manipulating content. A client
+ * can insert, update, and remove records in a content provider. For example,
+ * some settings may be configured before running the CTS tests, etc.
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>
+ * # Add "new_setting" secure setting with value "new_value".</br>
+ * adb shell content insert --uri content://settings/secure --bind name:s:new_setting
+ *  --bind value:s:new_value
+ * </li>
+ * <li>
+ * # Change "new_setting" secure setting to "newer_value" (You have to escape single quotes in
+ * the where clause).</br>
+ * adb shell content update --uri content://settings/secure --bind value:s:newer_value
+ *  --where "name=\'new_setting\'"
+ * </li>
+ * <li>
+ * # Remove "new_setting" secure setting.</br>
+ * adb shell content delete --uri content://settings/secure --where "name=\'new_setting\'"
+ * </li>
+ * <li>
+ * # Query \"name\" and \"value\" columns from secure settings where \"name\" is equal to"
+ *    \"new_setting\" and sort the result by name in ascending order.\n"
+ * adb shell content query --uri content://settings/secure --projection name:value
+ *  --where "name=\'new_setting\'" --sort \"name ASC\"
+ * </li>
+ * </ul>
+ * </p>
+ */
+public class Content {
+
+    private static final String USAGE =
+        "usage: adb shell content [subcommand] [options]\n"
+        + "\n"
+        + "usage: adb shell content insert --uri <URI> --bind <BINDING> [--bind <BINDING>...]\n"
+        + "  <URI> a content provider URI.\n"
+        + "  <BINDING> binds a typed value to a column and is formatted:\n"
+        + "  <COLUMN_NAME>:<TYPE>:<COLUMN_VALUE> where:\n"
+        + "  <TYPE> specifies data type such as:\n"
+        + "  b - boolean, s - string, i - integer, l - long, f - float, d - double\n"
+        + "  Example:\n"
+        + "  # Add \"new_setting\" secure setting with value \"new_value\".\n"
+        + "  adb shell content insert --uri content://settings/secure --bind name:s:new_setting"
+                + " --bind value:s:new_value\n"
+        + "\n"
+        + "usage: adb shell content update --uri <URI> [--where <WHERE>]\n"
+        + "  <WHERE> is a SQL style where clause in quotes (You have to escape single quotes"
+                + " - see example below).\n"
+        + "  Example:\n"
+        + "  # Change \"new_setting\" secure setting to \"newer_value\".\n"
+        + "  adb shell content update --uri content://settings/secure --bind"
+                + " value:s:newer_value --where \"name=\'new_setting\'\"\n"
+        + "\n"
+        + "usage: adb shell content delete --uri <URI> --bind <BINDING>"
+                + " [--bind <BINDING>...] [--where <WHERE>]\n"
+        + "  Example:\n"
+        + "  # Remove \"new_setting\" secure setting.\n"
+        + "  adb shell content delete --uri content://settings/secure "
+                + "--where \"name=\'new_setting\'\"\n"
+        + "\n"
+        + "usage: adb shell content query --uri <URI> [--projection <PROJECTION>]"
+                + " [--where <WHERE>] [--sort <SORT_ORDER>]\n"
+        + "  <PROJECTION> is a list of colon separated column names and is formatted:\n"
+        + "  <COLUMN_NAME>[:<COLUMN_NAME>...]\n"
+        + "  <SORT_OREDER> is the order in which rows in the result should be sorted.\n"
+        + "  Example:\n"
+        + "  # Select \"name\" and \"value\" columns from secure settings where \"name\" is "
+                + "equal to \"new_setting\" and sort the result by name in ascending order.\n"
+        + "  adb shell content query --uri content://settings/secure --projection name:value"
+                + " --where \"name=\'new_setting\'\" --sort \"name ASC\"\n"
+        + "\n";
+
+    private static class Parser {
+        private static final String ARGUMENT_INSERT = "insert";
+        private static final String ARGUMENT_DELETE = "delete";
+        private static final String ARGUMENT_UPDATE = "update";
+        private static final String ARGUMENT_QUERY = "query";
+        private static final String ARGUMENT_WHERE = "--where";
+        private static final String ARGUMENT_BIND = "--bind";
+        private static final String ARGUMENT_URI = "--uri";
+        private static final String ARGUMENT_PROJECTION = "--projection";
+        private static final String ARGUMENT_SORT = "--sort";
+        private static final String TYPE_BOOLEAN = "b";
+        private static final String TYPE_STRING = "s";
+        private static final String TYPE_INTEGER = "i";
+        private static final String TYPE_LONG = "l";
+        private static final String TYPE_FLOAT = "f";
+        private static final String TYPE_DOUBLE = "d";
+        private static final String COLON = ":";
+        private static final String ARGUMENT_PREFIX = "--";
+
+        private final Tokenizer mTokenizer;
+
+        public Parser(String[] args) {
+            mTokenizer = new Tokenizer(args);
+        }
+
+        public Command parseCommand() {
+            try {
+                String operation = mTokenizer.nextArg();
+                if (ARGUMENT_INSERT.equals(operation)) {
+                    return parseInsertCommand();
+                } else if (ARGUMENT_DELETE.equals(operation)) {
+                    return parseDeleteCommand();
+                } else if (ARGUMENT_UPDATE.equals(operation)) {
+                    return parseUpdateCommand();
+                } else if (ARGUMENT_QUERY.equals(operation)) {
+                    return parseQueryCommand();
+                } else {
+                    throw new IllegalArgumentException("Unsupported operation: " + operation);
+                }
+            } catch (IllegalArgumentException iae) {
+                System.out.println(USAGE);
+                System.out.println("[ERROR] " + iae.getMessage());
+                return null;
+            }
+        }
+
+        private InsertCommand parseInsertCommand() {
+            Uri uri = null;
+            ContentValues values = new ContentValues();
+            for (String argument; (argument = mTokenizer.nextArg()) != null;) {
+                if (ARGUMENT_URI.equals(argument)) {
+                    uri = Uri.parse(argumentValueRequired(argument));
+                } else if (ARGUMENT_BIND.equals(argument)) {
+                    parseBindValue(values);
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("Content provider URI not specified."
+                        + " Did you specify --uri argument?");
+            }
+            if (values.size() == 0) {
+                throw new IllegalArgumentException("Bindings not specified."
+                        + " Did you specify --bind argument(s)?");
+            }
+            return new InsertCommand(uri, values);
+        }
+
+        private DeleteCommand parseDeleteCommand() {
+            Uri uri = null;
+            String where = null;
+            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+                if (ARGUMENT_URI.equals(argument)) {
+                    uri = Uri.parse(argumentValueRequired(argument));
+                } else if (ARGUMENT_WHERE.equals(argument)) {
+                    where = argumentValueRequired(argument);
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("Content provider URI not specified."
+                        + " Did you specify --uri argument?");
+            }
+            return new DeleteCommand(uri, where);
+        }
+
+        private UpdateCommand parseUpdateCommand() {
+            Uri uri = null;
+            String where = null;
+            ContentValues values = new ContentValues();
+            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+                if (ARGUMENT_URI.equals(argument)) {
+                    uri = Uri.parse(argumentValueRequired(argument));
+                } else if (ARGUMENT_WHERE.equals(argument)) {
+                    where = argumentValueRequired(argument);
+                } else if (ARGUMENT_BIND.equals(argument)) {
+                    parseBindValue(values);
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("Content provider URI not specified."
+                        + " Did you specify --uri argument?");
+            }
+            if (values.size() == 0) {
+                throw new IllegalArgumentException("Bindings not specified."
+                        + " Did you specify --bind argument(s)?");
+            }
+            return new UpdateCommand(uri, values, where);
+        }
+
+        public QueryCommand parseQueryCommand() {
+            Uri uri = null;
+            String[] projection = null;
+            String sort = null;
+            String where = null;
+            for (String argument; (argument = mTokenizer.nextArg())!= null;) {
+                if (ARGUMENT_URI.equals(argument)) {
+                    uri = Uri.parse(argumentValueRequired(argument));
+                } else if (ARGUMENT_WHERE.equals(argument)) {
+                    where = argumentValueRequired(argument);
+                } else if (ARGUMENT_SORT.equals(argument)) {
+                    sort = argumentValueRequired(argument);
+                } else if (ARGUMENT_PROJECTION.equals(argument)) {
+                    projection = argumentValueRequired(argument).split("[\\s]*:[\\s]*");
+                } else {
+                    throw new IllegalArgumentException("Unsupported argument: " + argument);
+                }
+            }
+            if (uri == null) {
+                throw new IllegalArgumentException("Content provider URI not specified."
+                        + " Did you specify --uri argument?");
+            }
+            return new QueryCommand(uri, projection, where, sort);
+        }
+
+        private void parseBindValue(ContentValues values) {
+            String argument = mTokenizer.nextArg();
+            if (TextUtils.isEmpty(argument)) {
+                throw new IllegalArgumentException("Binding not well formed: " + argument);
+            }
+            String[] binding = argument.split(COLON);
+            if (binding.length != 3) {
+                throw new IllegalArgumentException("Binding not well formed: " + argument);
+            }
+            String column = binding[0];
+            String type = binding[1];
+            String value = binding[2];
+            if (TYPE_STRING.equals(type)) {
+                values.put(column, value);
+            } else if (TYPE_BOOLEAN.equalsIgnoreCase(type)) {
+                values.put(column, Boolean.parseBoolean(value));
+            } else if (TYPE_INTEGER.equalsIgnoreCase(type) || TYPE_LONG.equalsIgnoreCase(type)) {
+                values.put(column, Long.parseLong(value));
+            } else if (TYPE_FLOAT.equalsIgnoreCase(type) || TYPE_DOUBLE.equalsIgnoreCase(type)) {
+                values.put(column, Double.parseDouble(value));
+            } else {
+                throw new IllegalArgumentException("Unsupported type: " + type);
+            }
+        }
+
+        private String argumentValueRequired(String argument) {
+            String value = mTokenizer.nextArg();
+            if (TextUtils.isEmpty(value) || value.startsWith(ARGUMENT_PREFIX)) {
+                throw new IllegalArgumentException("No value for argument: " + argument);
+            }
+            return value;
+        }
+    }
+
+    private static class Tokenizer {
+        private final String[] mArgs;
+        private int mNextArg;
+
+        public Tokenizer(String[] args) {
+            mArgs = args;
+        }
+
+        private String nextArg() {
+            if (mNextArg < mArgs.length) {
+                return mArgs[mNextArg++];
+            } else {
+                return null;
+            }
+        }
+    }
+
+    private static abstract class Command {
+        final Uri mUri;
+
+        public Command(Uri uri) {
+            mUri = uri;
+        }
+
+        public final void execute() {
+            String providerName = mUri.getAuthority();
+            try {
+                IActivityManager activityManager = ActivityManagerNative.getDefault();
+                IContentProvider provider = null;
+                IBinder token = new Binder();
+                try {
+                    ContentProviderHolder holder = activityManager.getContentProviderExternal(
+                            providerName, token);
+                    if (holder == null) {
+                        throw new IllegalStateException("Could not find provider: " + providerName);
+                    }
+                    provider = holder.provider;
+                    onExecute(provider);
+                } finally {
+                    if (provider != null) {
+                        activityManager.removeContentProviderExternal(providerName, token);
+                    }
+                }
+            } catch (Exception e) {
+                System.err.println("Error while accessing provider:" + providerName);
+                e.printStackTrace();
+            }
+        }
+
+        protected abstract void onExecute(IContentProvider provider) throws Exception;
+    }
+
+    private static class InsertCommand extends Command {
+        final ContentValues mContentValues;
+
+        public InsertCommand(Uri uri, ContentValues contentValues) {
+            super(uri);
+            mContentValues = contentValues;
+        }
+
+        @Override
+        public void onExecute(IContentProvider provider) throws Exception {
+            provider.insert(mUri, mContentValues);
+        }
+    }
+
+    private static class DeleteCommand extends Command {
+        final String mWhere;
+
+        public DeleteCommand(Uri uri, String where) {
+            super(uri);
+            mWhere = where;
+        }
+
+        @Override
+        public void onExecute(IContentProvider provider) throws Exception {
+            provider.delete(mUri, mWhere, null);
+        }
+    }
+
+    private static class QueryCommand extends DeleteCommand {
+        final String[] mProjection;
+        final String mSortOrder;
+
+        public QueryCommand(Uri uri, String[] projection, String where, String sortOrder) {
+            super(uri, where);
+            mProjection = projection;
+            mSortOrder = sortOrder;
+        }
+
+        @Override
+        public void onExecute(IContentProvider provider) throws Exception {
+            Cursor cursor = provider.query(mUri, mProjection, mWhere, null, mSortOrder, null);
+            if (cursor == null) {
+                System.out.println("No result found.");
+                return;
+            }
+            try {
+                if (cursor.moveToFirst()) {
+                    int rowIndex = 0;
+                    StringBuilder builder = new StringBuilder();
+                    do {
+                        builder.setLength(0);
+                        builder.append("Row: ").append(rowIndex).append(" ");
+                        rowIndex++;
+                        final int columnCount = cursor.getColumnCount();
+                        for (int i = 0; i < columnCount; i++) {
+                            if (i > 0) {
+                                builder.append(", ");
+                            }
+                            String columnName = cursor.getColumnName(i);
+                            String columnValue = null;
+                            final int columnIndex = cursor.getColumnIndex(columnName);
+                            final int type = cursor.getType(columnIndex);
+                            switch (type) {
+                                case Cursor.FIELD_TYPE_FLOAT:
+                                    columnValue = String.valueOf(cursor.getFloat(columnIndex));
+                                    break;
+                                case Cursor.FIELD_TYPE_INTEGER:
+                                    columnValue = String.valueOf(cursor.getInt(columnIndex));
+                                    break;
+                                case Cursor.FIELD_TYPE_STRING:
+                                    columnValue = cursor.getString(columnIndex);
+                                    break;
+                                case Cursor.FIELD_TYPE_BLOB:
+                                    columnValue = "BLOB";
+                                    break;
+                                case Cursor.FIELD_TYPE_NULL:
+                                    columnValue = "NULL";
+                                    break;
+                            }
+                            builder.append(columnName).append("=").append(columnValue);
+                        }
+                        System.out.println(builder);
+                    } while (cursor.moveToNext());
+                } else {
+                    System.out.println("No reuslt found.");
+                }
+            } finally {
+                cursor.close();
+            }
+        }
+    }
+
+    private static class UpdateCommand extends InsertCommand {
+        final String mWhere;
+
+        public UpdateCommand(Uri uri, ContentValues contentValues, String where) {
+            super(uri, contentValues);
+            mWhere = where;
+        }
+
+        @Override
+        public void onExecute(IContentProvider provider) throws Exception {
+            provider.update(mUri, mContentValues, mWhere, null);
+        }
+    }
+
+    public static void main(String[] args) {
+        Parser parser = new Parser(args);
+        Command command = parser.parseCommand();
+        if (command != null) {
+            command.execute();
+        }
+    }
+}
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index bee5880..90dfe76 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -49,7 +49,6 @@
 {
     switch (f) {
         case PIXEL_FORMAT_A_8:
-        case PIXEL_FORMAT_L_8:
             return SkBitmap::kA8_Config;
         case PIXEL_FORMAT_RGB_565:
             return SkBitmap::kRGB_565_Config;
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index cfc2d16..71c5622 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -43,6 +43,8 @@
     { AID_RADIO, "isms" },
     { AID_RADIO, "iphonesubinfo" },
     { AID_RADIO, "simphonebook" },
+    { AID_MEDIA, "common_time.clock" },
+    { AID_MEDIA, "common_time.config" },
 };
 
 void *svcmgr_handle;
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index c9468eb..882dd6b 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -30,14 +30,14 @@
     void setServiceInfo(in AccessibilityServiceInfo info);
 
     /**
-     * Finds an {@link AccessibilityNodeInfo} by accessibility id.
+     * Finds an {@link android.view.accessibility.AccessibilityNodeInfo} by accessibility id.
      *
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
      *     to start from the root.
      * @param interactionId The id of the interaction for matching with the callback result.
      * @param callback Callback which to receive the result.
@@ -49,17 +49,16 @@
         IAccessibilityInteractionConnectionCallback callback, long threadId);
 
     /**
-     * Finds {@link AccessibilityNodeInfo}s by View text. The match is case
-     * insensitive containment. The search is performed in the window whose
-     * id is specified and starts from the node whose accessibility id is
-     * specified.
+     * Finds {@link android.view.accessibility.AccessibilityNodeInfo}s by View text.
+     * The match is case insensitive containment. The search is performed in the window
+     * whose id is specified and starts from the node whose accessibility id is specified.
      *
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
      *     to start from the root.
      * @param text The searched text.
      * @param interactionId The id of the interaction for matching with the callback result.
@@ -72,16 +71,16 @@
         long threadId);
 
     /**
-     * Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
-     * the window whose id is specified and starts from the node whose accessibility
-     * id is specified.
+     * Finds an {@link android.view.accessibility.AccessibilityNodeInfo} by View id. The search
+     * is performed in the window whose id is specified and starts from the node whose
+     * accessibility id is specified.
      *
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
      *     to start from the root.
      * @param id The id of the node.
      * @param interactionId The id of the interaction for matching with the callback result.
@@ -94,14 +93,15 @@
         long threadId);
 
     /**
-     * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
+     * Performs an accessibility action on an
+     * {@link android.view.accessibility.AccessibilityNodeInfo}.
      *
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
      *     to start from the root.
      * @param action The action to perform.
      * @param interactionId The id of the interaction for matching with the callback result.
diff --git a/core/java/android/accessibilityservice/UiTestAutomationBridge.java b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
index 616b796..334981a 100644
--- a/core/java/android/accessibilityservice/UiTestAutomationBridge.java
+++ b/core/java/android/accessibilityservice/UiTestAutomationBridge.java
@@ -49,12 +49,14 @@
 
     private static final String LOG_TAG = UiTestAutomationBridge.class.getSimpleName();
 
-    public static final int ACTIVE_WINDOW_ID = -1;
-
-    public static final long ROOT_NODE_ID = -1;
-
     private static final int TIMEOUT_REGISTER_SERVICE = 5000;
 
+    public static final int ACTIVE_WINDOW_ID = AccessibilityNodeInfo.ACTIVE_WINDOW_ID;
+
+    public static final long ROOT_NODE_ID = AccessibilityNodeInfo.ROOT_NODE_ID;
+
+    public static final int UNDEFINED = -1;
+
     private final Object mLock = new Object();
 
     private volatile int mConnectionId = AccessibilityInteractionClient.NO_ID;
@@ -63,8 +65,6 @@
 
     private AccessibilityEvent mLastEvent;
 
-    private AccessibilityEvent mLastWindowStateChangeEvent;
-
     private volatile boolean mWaitingForEventDelivery;
 
     private volatile boolean mUnprocessedEventAvailable;
@@ -141,17 +141,8 @@
                 synchronized (mLock) {
                     while (true) {
                         mLastEvent = AccessibilityEvent.obtain(event);
-
-                        final int eventType = event.getEventType();
-                        if (eventType == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
-                                || eventType == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) {
-                            if (mLastWindowStateChangeEvent != null) {
-                                mLastWindowStateChangeEvent.recycle();
-                            }
-                            mLastWindowStateChangeEvent = mLastEvent;
-                        }
-
                         if (!mWaitingForEventDelivery) {
+                            mLock.notifyAll();
                             break;
                         }
                         if (!mUnprocessedEventAvailable) {
@@ -295,6 +286,43 @@
     }
 
     /**
+     * Waits for the accessibility event stream to become idle, which is not to
+     * have received a new accessibility event within <code>idleTimeout</code>,
+     * and do so within a maximal global timeout as specified by
+     * <code>globalTimeout</code>.
+     *
+     * @param idleTimeout The timeout between two event to consider the device idle.
+     * @param globalTimeout The maximal global timeout in which to wait for idle.
+     */
+    public void waitForIdle(long idleTimeout, long globalTimeout) {
+        final long startTimeMillis = SystemClock.uptimeMillis();
+        long lastEventTime = (mLastEvent != null)
+                ? mLastEvent.getEventTime() : SystemClock.uptimeMillis();
+        synchronized (mLock) {
+            while (true) {
+                final long currentTimeMillis = SystemClock.uptimeMillis();
+                final long sinceLastEventTimeMillis = currentTimeMillis - lastEventTime;
+                if (sinceLastEventTimeMillis > idleTimeout) {
+                    return;
+                }
+                if (mLastEvent != null) {
+                    lastEventTime = mLastEvent.getEventTime();
+                }
+                final long elapsedTimeMillis = SystemClock.uptimeMillis() - startTimeMillis;
+                final long remainingTimeMillis = globalTimeout - elapsedTimeMillis;
+                if (remainingTimeMillis <= 0) {
+                    return;
+                }
+                try {
+                     mLock.wait(idleTimeout);
+                } catch (InterruptedException e) {
+                     /* ignore */
+                }
+            }
+        }
+    }
+
+    /**
      * Finds an {@link AccessibilityNodeInfo} by accessibility id in the active
      * window. The search is performed from the root node.
      *
@@ -310,8 +338,8 @@
     /**
      * Finds an {@link AccessibilityNodeInfo} by accessibility id.
      *
-     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
-     *     to query the currently active window.
+     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID} to query
+     *     the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id for
      *     which to search.
      * @return The current window scale, where zero means a failure.
@@ -341,10 +369,10 @@
      * the window whose id is specified and starts from the node whose accessibility
      * id is specified.
      *
-     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
-     *     to query the currently active window.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link  #ACTIVE_WINDOW_ID} to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
-     *     where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
+     *     where to start the search. Use {@link  #ROOT_NODE_ID} to start from the root.
      * @return The current window scale, where zero means a failure.
      */
     public AccessibilityNodeInfo findAccessibilityNodeInfoByViewId(int accessibilityWindowId,
@@ -374,8 +402,8 @@
      * id is specified and starts from the node whose accessibility id is
      * specified.
      *
-     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
-     *     to query the currently active window.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link #ACTIVE_WINDOW_ID} to query the currently active window.
      * @param accessibilityNodeId A unique view id or virtual descendant id from
      *     where to start the search. Use {@link #ROOT_NODE_ID} to start from the root.
      * @param text The searched text.
@@ -406,8 +434,8 @@
     /**
      * Performs an accessibility action on an {@link AccessibilityNodeInfo}.
      *
-     * @param accessibilityWindowId A unique window id. Use {@link #ACTIVE_WINDOW_ID}
-     *     to query the currently active window.
+     * @param accessibilityWindowId A unique window id. Use
+     *     {@link #ACTIVE_WINDOW_ID} to query the currently active window.
      * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
      * @param action The action to perform.
      * @return Whether the action was performed.
@@ -427,16 +455,16 @@
      * @return The root info.
      */
     public AccessibilityNodeInfo getRootAccessibilityNodeInfoInActiveWindow() {
-        synchronized (mLock) {
-            if (mLastWindowStateChangeEvent != null) {
-                return mLastWindowStateChangeEvent.getSource();
-            }
-        }
-        return null;
+        // Cache the id to avoid locking
+        final int connectionId = mConnectionId;
+        ensureValidConnection(connectionId);
+        return AccessibilityInteractionClient.getInstance()
+                .findAccessibilityNodeInfoByAccessibilityId(connectionId, ACTIVE_WINDOW_ID,
+                        ROOT_NODE_ID);
     }
 
     private void ensureValidConnection(int connectionId) {
-        if (connectionId == AccessibilityInteractionClient.NO_ID) {
+        if (connectionId == UNDEFINED) {
             throw new IllegalStateException("UiAutomationService not connected."
                     + " Did you call #register()?");
         }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 5a36466..24079a5d 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -581,6 +581,21 @@
             return true;
         }
 
+        case GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String name = data.readString();
+            IBinder token = data.readStrongBinder();
+            ContentProviderHolder cph = getContentProviderExternal(name, token);
+            reply.writeNoException();
+            if (cph != null) {
+                reply.writeInt(1);
+                cph.writeToParcel(reply, 0);
+            } else {
+                reply.writeInt(0);
+            }
+            return true;
+        }
+
         case PUBLISH_CONTENT_PROVIDERS_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder b = data.readStrongBinder();
@@ -601,7 +616,16 @@
             reply.writeNoException();
             return true;
         }
-        
+
+        case REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            String name = data.readString();
+            IBinder token = data.readStrongBinder();
+            removeContentProviderExternal(name, token);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_RUNNING_SERVICE_CONTROL_PANEL_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             ComponentName comp = ComponentName.CREATOR.createFromParcel(data);
@@ -2178,6 +2202,25 @@
         reply.recycle();
         return cph;
     }
+    public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
+            throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(name);
+        data.writeStrongBinder(token);
+        mRemote.transact(GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
+        reply.readException();
+        int res = reply.readInt();
+        ContentProviderHolder cph = null;
+        if (res != 0) {
+            cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
+        }
+        data.recycle();
+        reply.recycle();
+        return cph;
+    }
     public void publishContentProviders(IApplicationThread caller,
                                         List<ContentProviderHolder> providers) throws RemoteException
     {
@@ -2204,7 +2247,19 @@
         data.recycle();
         reply.recycle();
     }
-    
+
+    public void removeContentProviderExternal(String name, IBinder token) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeString(name);
+        data.writeStrongBinder(token);
+        mRemote.transact(REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     public PendingIntent getRunningServiceControlPanel(ComponentName service)
             throws RemoteException
     {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index ebf692a..6d5cce5 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -911,6 +911,19 @@
         }
     }
 
+    /** @hide */
+    @Override
+    public void sendBroadcast(Intent intent, int userId) {
+        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+        try {
+            intent.setAllowFds(false);
+            ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
+                    intent, resolvedType, null, Activity.RESULT_OK, null, null, null, false, false,
+                    userId);
+        } catch (RemoteException e) {
+        }
+    }
+
     @Override
     public void sendBroadcast(Intent intent, String receiverPermission) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 7deb615..53a71db 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -150,8 +150,11 @@
             Bitmap thumbnail, CharSequence description) throws RemoteException;
     public ContentProviderHolder getContentProvider(IApplicationThread caller,
             String name) throws RemoteException;
+    public ContentProviderHolder getContentProviderExternal(String name, IBinder token)
+            throws RemoteException;
     public void removeContentProvider(IApplicationThread caller,
             String name) throws RemoteException;
+    public void removeContentProviderExternal(String name, IBinder token) throws RemoteException;
     public void publishContentProviders(IApplicationThread caller,
             List<ContentProviderHolder> providers) throws RemoteException;
     public PendingIntent getRunningServiceControlPanel(ComponentName service)
@@ -415,7 +418,7 @@
                 source.readStrongBinder());
             noReleaseNeeded = source.readInt() != 0;
         }
-    };
+    }
 
     /** Information returned after waiting for an activity start. */
     public static class WaitResult implements Parcelable {
@@ -601,4 +604,6 @@
     int SHOW_BOOT_MESSAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+137;
     int DISMISS_KEYGUARD_ON_NEXT_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+138;
     int KILL_ALL_BACKGROUND_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+139;
+    int GET_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+140;
+    int REMOVE_CONTENT_PROVIDER_EXTERNAL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+141;
 }
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 6d4cdae..a1198de 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -905,6 +905,16 @@
     public abstract void sendBroadcast(Intent intent);
 
     /**
+     * Same as #sendBroadcast(Intent intent), but for a specific user. Used by the system only.
+     * @param intent the intent to broadcast
+     * @param userId user to send the intent to
+     * @hide
+     */
+    public void sendBroadcast(Intent intent, int userId) {
+        throw new RuntimeException("Not implemented. Must override in a subclass.");
+    }
+
+    /**
      * Broadcast the given intent to all interested BroadcastReceivers, allowing
      * an optional required permission to be enforced.  This
      * call is asynchronous; it returns immediately, and you will continue
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index cd8d87f..5ba9dcc 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -294,6 +294,12 @@
         mBase.sendBroadcast(intent);
     }
 
+    /** @hide */
+    @Override
+    public void sendBroadcast(Intent intent, int userId) {
+        mBase.sendBroadcast(intent, userId);
+    }
+
     @Override
     public void sendBroadcast(Intent intent, String receiverPermission) {
         mBase.sendBroadcast(intent, receiverPermission);
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index aeb5d92..3fdf246 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -616,6 +616,7 @@
             Message msg = Message.obtain();
             msg.what = 0;
             msg.obj = t;
+            msg.setAsynchronous(true);
             mHandler.sendMessage(msg);
         }
     }
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index f94d320..06c6c6e 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -25,15 +25,17 @@
 import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509TrustManager;
 import org.apache.harmony.security.provider.cert.X509CertImpl;
 import org.apache.harmony.xnet.provider.jsse.SSLParametersImpl;
+import org.apache.harmony.xnet.provider.jsse.TrustManagerImpl;
 
 /**
  * Class responsible for all server certificate validation functionality
  *
  * {@hide}
  */
-class CertificateChainValidator {
+public class CertificateChainValidator {
 
     /**
      * The singleton instance of the certificate chain validator
@@ -122,6 +124,18 @@
     }
 
     /**
+     * Handles updates to credential storage.
+     */
+    public static void handleTrustStorageUpdate() {
+
+        X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultTrustManager();
+        if( x509TrustManager instanceof TrustManagerImpl ) {
+            TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
+            trustManager.handleTrustStorageUpdate();
+        }
+    }
+
+    /**
      * Common code of doHandshakeAndValidateServerCertificates and verifyServerCertificates.
      * Calls DomainNamevalidator to verify the domain, and TrustManager to verify the certs.
      * @param chain the cert chain in X509 cert format.
diff --git a/core/java/android/os/CommonClock.java b/core/java/android/os/CommonClock.java
new file mode 100644
index 0000000..3a1da97
--- /dev/null
+++ b/core/java/android/os/CommonClock.java
@@ -0,0 +1,414 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import java.util.NoSuchElementException;
+import static libcore.io.OsConstants.*;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.CommonTimeUtils;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Used for accessing the android common time service's common clock and receiving notifications
+ * about common time synchronization status changes.
+ * @hide
+ */
+public class CommonClock {
+    /**
+     * Sentinel value returned by {@link #getTime()} and {@link #getEstimatedError()} when the
+     * common time service is not able to determine the current common time due to a lack of
+     * synchronization.
+     */
+    public static final long TIME_NOT_SYNCED = -1;
+
+    /**
+     * Sentinel value returned by {@link #getTimelineId()} when the common time service is not
+     * currently synced to any timeline.
+     */
+    public static final long INVALID_TIMELINE_ID = 0;
+
+    /**
+     * Sentinel value returned by {@link #getEstimatedError()} when the common time service is not
+     * currently synced to any timeline.
+     */
+    public static final int ERROR_ESTIMATE_UNKNOWN = 0x7FFFFFFF;
+
+    /**
+     * Value used by {@link #getState()} to indicate that there was an internal error while
+     * attempting to determine the state of the common time service.
+     */
+    public static final int STATE_INVALID = -1;
+
+    /**
+     * Value used by {@link #getState()} to indicate that the common time service is in its initial
+     * state and attempting to find the current timeline master, if any.  The service will
+     * transition to either {@link #STATE_CLIENT} if it finds an active master, or to
+     * {@link #STATE_MASTER} if no active master is found and this client becomes the master of a
+     * new timeline.
+     */
+    public static final int STATE_INITIAL = 0;
+
+    /**
+     * Value used by {@link #getState()} to indicate that the common time service is in its client
+     * state and is synchronizing its time to a different timeline master on the network.
+     */
+    public static final int STATE_CLIENT = 1;
+
+    /**
+     * Value used by {@link #getState()} to indicate that the common time service is in its master
+     * state and is serving as the timeline master for other common time service clients on the
+     * network.
+     */
+    public static final int STATE_MASTER = 2;
+
+    /**
+     * Value used by {@link #getState()} to indicate that the common time service is in its Ronin
+     * state.  Common time service instances in the client state enter the Ronin state after their
+     * timeline master becomes unreachable on the network.  Common time services who enter the Ronin
+     * state will begin a new master election for the timeline they were recently clients of.  As
+     * clients detect they are not the winner and drop out of the election, they will transition to
+     * the {@link #STATE_WAIT_FOR_ELECTION} state.  When there is only one client remaining in the
+     * election, it will assume ownership of the timeline and transition to the
+     * {@link #STATE_MASTER} state.  During the election, all clients will allow their timeline to
+     * drift without applying correction.
+     */
+    public static final int STATE_RONIN = 3;
+
+    /**
+     * Value used by {@link #getState()} to indicate that the common time service is waiting for a
+     * master election to conclude and for the new master to announce itself before transitioning to
+     * the {@link #STATE_CLIENT} state.  If no new master announces itself within the timeout
+     * threshold, the time service will transition back to the {@link #STATE_RONIN} state in order
+     * to restart the election.
+     */
+    public static final int STATE_WAIT_FOR_ELECTION = 4;
+
+    /**
+     * Name of the underlying native binder service
+     */
+    public static final String SERVICE_NAME = "common_time.clock";
+
+    /**
+     * Class constructor.
+     * @throws android.os.RemoteException
+     */
+    public CommonClock()
+    throws RemoteException {
+        mRemote = ServiceManager.getService(SERVICE_NAME);
+        if (null == mRemote)
+            throw new RemoteException();
+
+        mInterfaceDesc = mRemote.getInterfaceDescriptor();
+        mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
+        mRemote.linkToDeath(mDeathHandler, 0);
+        registerTimelineChangeListener();
+    }
+
+    /**
+     * Handy class factory method.
+     */
+    static public CommonClock create() {
+        CommonClock retVal;
+
+        try {
+            retVal = new CommonClock();
+        }
+        catch (RemoteException e) {
+            retVal = null;
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Release all native resources held by this {@link android.os.CommonClock} instance.  Once
+     * resources have been released, the {@link android.os.CommonClock} instance is disconnected from
+     * the native service and will throw a {@link android.os.RemoteException} if any of its
+     * methods are called.  Clients should always call release on their client instances before
+     * releasing their last Java reference to the instance.  Failure to do this will cause
+     * non-deterministic native resource reclamation and may cause the common time service to remain
+     * active on the network for longer than it should.
+     */
+    public void release() {
+        unregisterTimelineChangeListener();
+        if (null != mRemote) {
+            try {
+                mRemote.unlinkToDeath(mDeathHandler, 0);
+            }
+            catch (NoSuchElementException e) { }
+            mRemote = null;
+        }
+        mUtils = null;
+    }
+
+    /**
+     * Gets the common clock's current time.
+     *
+     * @return a signed 64-bit value representing the current common time in microseconds, or the
+     * special value {@link #TIME_NOT_SYNCED} if the common time service is currently not
+     * synchronized.
+     * @throws android.os.RemoteException
+     */
+    public long getTime()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetLong(METHOD_GET_COMMON_TIME, TIME_NOT_SYNCED);
+    }
+
+    /**
+     * Gets the current estimation of common clock's synchronization accuracy from the common time
+     * service.
+     *
+     * @return a signed 32-bit value representing the common time service's estimation of
+     * synchronization accuracy in microseconds, or the special value
+     * {@link #ERROR_ESTIMATE_UNKNOWN} if the common time service is currently not synchronized.
+     * Negative values indicate that the local server estimates that the nominal common time is
+     * behind the local server's time (in other words, the local clock is running fast) Positive
+     * values indicate that the local server estimates that the nominal common time is ahead of the
+     * local server's time (in other words, the local clock is running slow)
+     * @throws android.os.RemoteException
+     */
+    public int getEstimatedError()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetInt(METHOD_GET_ESTIMATED_ERROR, ERROR_ESTIMATE_UNKNOWN);
+    }
+
+    /**
+     * Gets the ID of the timeline the common time service is currently synchronizing its clock to.
+     *
+     * @return a long representing the unique ID of the timeline the common time service is
+     * currently synchronizing with, or {@link #INVALID_TIMELINE_ID} if the common time service is
+     * currently not synchronized.
+     * @throws android.os.RemoteException
+     */
+    public long getTimelineId()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetLong(METHOD_GET_TIMELINE_ID, INVALID_TIMELINE_ID);
+    }
+
+    /**
+     * Gets the current state of this clock's common time service in the the master election
+     * algorithm.
+     *
+     * @return a integer indicating the current state of the this clock's common time service in the
+     * master election algorithm or {@link #STATE_INVALID} if there is an internal error.
+     * @throws android.os.RemoteException
+     */
+    public int getState()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetInt(METHOD_GET_STATE, STATE_INVALID);
+    }
+
+    /**
+     * Gets the IP address and UDP port of the current timeline master.
+     *
+     * @return an InetSocketAddress containing the IP address and UDP port of the current timeline
+     * master, or null if there is no current master.
+     * @throws android.os.RemoteException
+     */
+    public InetSocketAddress getMasterAddr()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ADDRESS);
+    }
+
+    /**
+     * The OnTimelineChangedListener interface defines a method called by the
+     * {@link android.os.CommonClock} instance to indicate that the time synchronization service has
+     * either synchronized with a new timeline, or is no longer a member of any timeline.  The
+     * client application can implement this interface and register the listener with the
+     * {@link #setTimelineChangedListener(OnTimelineChangedListener)} method.
+     */
+    public interface OnTimelineChangedListener  {
+        /**
+         * Method called when the time service's timeline has changed.
+         *
+         * @param newTimelineId a long which uniquely identifies the timeline the time
+         * synchronization service is now a member of, or {@link #INVALID_TIMELINE_ID} if the the
+         * service is not synchronized to any timeline.
+         */
+        void onTimelineChanged(long newTimelineId);
+    }
+
+    /**
+     * Registers an OnTimelineChangedListener interface.
+     * <p>Call this method with a null listener to stop receiving server death notifications.
+     */
+    public void setTimelineChangedListener(OnTimelineChangedListener listener) {
+        synchronized (mListenerLock) {
+            mTimelineChangedListener = listener;
+        }
+    }
+
+    /**
+     * The OnServerDiedListener interface defines a method called by the
+     * {@link android.os.CommonClock} instance to indicate that the connection to the native media
+     * server has been broken and that the {@link android.os.CommonClock} instance will need to be
+     * released and re-created.  The client application can implement this interface and register
+     * the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
+     */
+    public interface OnServerDiedListener  {
+        /**
+         * Method called when the native media server has died.  <p>If the native common time
+         * service encounters a fatal error and needs to restart, the binder connection from the
+         * {@link android.os.CommonClock} instance to the common time service will be broken.  To
+         * restore functionality, clients should {@link #release()} their old visualizer and create
+         * a new instance.
+         */
+        void onServerDied();
+    }
+
+    /**
+     * Registers an OnServerDiedListener interface.
+     * <p>Call this method with a null listener to stop receiving server death notifications.
+     */
+    public void setServerDiedListener(OnServerDiedListener listener) {
+        synchronized (mListenerLock) {
+            mServerDiedListener = listener;
+        }
+    }
+
+    protected void finalize() throws Throwable { release(); }
+
+    private void throwOnDeadServer() throws RemoteException {
+        if ((null == mRemote) || (null == mUtils))
+            throw new RemoteException();
+    }
+
+    private final Object mListenerLock = new Object();
+    private OnTimelineChangedListener mTimelineChangedListener = null;
+    private OnServerDiedListener mServerDiedListener = null;
+
+    private IBinder mRemote = null;
+    private String mInterfaceDesc = "";
+    private CommonTimeUtils mUtils;
+
+    private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
+        public void binderDied() {
+            synchronized (mListenerLock) {
+                if (null != mServerDiedListener)
+                    mServerDiedListener.onServerDied();
+            }
+        }
+    };
+
+    private class TimelineChangedListener extends Binder {
+        @Override
+        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+        throws RemoteException {
+            switch (code) {
+                case METHOD_CBK_ON_TIMELINE_CHANGED:
+                    data.enforceInterface(DESCRIPTOR);
+                    long timelineId = data.readLong();
+                    synchronized (mListenerLock) {
+                        if (null != mTimelineChangedListener)
+                            mTimelineChangedListener.onTimelineChanged(timelineId);
+                    }
+                    return true;
+            }
+
+            return super.onTransact(code, data, reply, flags);
+        }
+
+        private static final String DESCRIPTOR = "android.os.ICommonClockListener";
+    };
+
+    private TimelineChangedListener mCallbackTgt = null;
+
+    private void registerTimelineChangeListener() throws RemoteException {
+        if (null != mCallbackTgt)
+            return;
+
+        boolean success = false;
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+        mCallbackTgt = new TimelineChangedListener();
+
+        try {
+            data.writeInterfaceToken(mInterfaceDesc);
+            data.writeStrongBinder(mCallbackTgt);
+            mRemote.transact(METHOD_REGISTER_LISTENER, data, reply, 0);
+            success = (0 == reply.readInt());
+        }
+        catch (RemoteException e) {
+            success = false;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+
+        // Did we catch a remote exception or fail to register our callback target?  If so, our
+        // object must already be dead (or be as good as dead).  Clear out all of our state so that
+        // our other methods will properly indicate a dead object.
+        if (!success) {
+            mCallbackTgt = null;
+            mRemote = null;
+            mUtils = null;
+        }
+    }
+
+    private void unregisterTimelineChangeListener() {
+        if (null == mCallbackTgt)
+            return;
+
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+
+        try {
+            data.writeInterfaceToken(mInterfaceDesc);
+            data.writeStrongBinder(mCallbackTgt);
+            mRemote.transact(METHOD_UNREGISTER_LISTENER, data, reply, 0);
+        }
+        catch (RemoteException e) { }
+        finally {
+            reply.recycle();
+            data.recycle();
+            mCallbackTgt = null;
+        }
+    }
+
+    private static final int METHOD_IS_COMMON_TIME_VALID = IBinder.FIRST_CALL_TRANSACTION;
+    private static final int METHOD_COMMON_TIME_TO_LOCAL_TIME = METHOD_IS_COMMON_TIME_VALID + 1;
+    private static final int METHOD_LOCAL_TIME_TO_COMMON_TIME = METHOD_COMMON_TIME_TO_LOCAL_TIME + 1;
+    private static final int METHOD_GET_COMMON_TIME = METHOD_LOCAL_TIME_TO_COMMON_TIME + 1;
+    private static final int METHOD_GET_COMMON_FREQ = METHOD_GET_COMMON_TIME + 1;
+    private static final int METHOD_GET_LOCAL_TIME = METHOD_GET_COMMON_FREQ + 1;
+    private static final int METHOD_GET_LOCAL_FREQ = METHOD_GET_LOCAL_TIME + 1;
+    private static final int METHOD_GET_ESTIMATED_ERROR = METHOD_GET_LOCAL_FREQ + 1;
+    private static final int METHOD_GET_TIMELINE_ID = METHOD_GET_ESTIMATED_ERROR + 1;
+    private static final int METHOD_GET_STATE = METHOD_GET_TIMELINE_ID + 1;
+    private static final int METHOD_GET_MASTER_ADDRESS = METHOD_GET_STATE + 1;
+    private static final int METHOD_REGISTER_LISTENER = METHOD_GET_MASTER_ADDRESS + 1;
+    private static final int METHOD_UNREGISTER_LISTENER = METHOD_REGISTER_LISTENER + 1;
+
+    private static final int METHOD_CBK_ON_TIMELINE_CHANGED = IBinder.FIRST_CALL_TRANSACTION;
+}
diff --git a/core/java/android/os/CommonTimeConfig.java b/core/java/android/os/CommonTimeConfig.java
new file mode 100644
index 0000000..3355ee3
--- /dev/null
+++ b/core/java/android/os/CommonTimeConfig.java
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.util.NoSuchElementException;
+
+import android.os.CommonTimeUtils;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+/**
+ * Used for configuring and controlling the status of the android common time service.
+ * @hide
+ */
+public class CommonTimeConfig {
+    /**
+     * Successful operation.
+     */
+    public static final int SUCCESS = 0;
+    /**
+     * Unspecified error.
+     */
+    public static final int ERROR = -1;
+    /**
+     * Operation failed due to bad parameter value.
+     */
+    public static final int ERROR_BAD_VALUE = -4;
+    /**
+     * Operation failed due to dead remote object.
+     */
+    public static final int ERROR_DEAD_OBJECT = -7;
+
+    /**
+     * Sentinel value returned by {@link #getMasterElectionGroupId()} when an error occurs trying to
+     * fetch the master election group.
+     */
+    public static final long INVALID_GROUP_ID = -1;
+
+    /**
+     * Name of the underlying native binder service
+     */
+    public static final String SERVICE_NAME = "common_time.config";
+
+    /**
+     * Class constructor.
+     * @throws android.os.RemoteException
+     */
+    public CommonTimeConfig()
+    throws RemoteException {
+        mRemote = ServiceManager.getService(SERVICE_NAME);
+        if (null == mRemote)
+            throw new RemoteException();
+
+        mInterfaceDesc = mRemote.getInterfaceDescriptor();
+        mUtils = new CommonTimeUtils(mRemote, mInterfaceDesc);
+        mRemote.linkToDeath(mDeathHandler, 0);
+    }
+
+    /**
+     * Handy class factory method.
+     */
+    static public CommonTimeConfig create() {
+        CommonTimeConfig retVal;
+
+        try {
+            retVal = new CommonTimeConfig();
+        }
+        catch (RemoteException e) {
+            retVal = null;
+        }
+
+        return retVal;
+    }
+
+    /**
+     * Release all native resources held by this {@link android.os.CommonTimeConfig} instance.  Once
+     * resources have been released, the {@link android.os.CommonTimeConfig} instance is
+     * disconnected from the native service and will throw a {@link android.os.RemoteException} if
+     * any of its methods are called.  Clients should always call release on their client instances
+     * before releasing their last Java reference to the instance.  Failure to do this will cause
+     * non-deterministic native resource reclamation and may cause the common time service to remain
+     * active on the network for longer than it should.
+     */
+    public void release() {
+        if (null != mRemote) {
+            try {
+                mRemote.unlinkToDeath(mDeathHandler, 0);
+            }
+            catch (NoSuchElementException e) { }
+            mRemote = null;
+        }
+        mUtils = null;
+    }
+
+    /**
+     * Gets the current priority of the common time service used in the master election protocol.
+     *
+     * @return an 8 bit value indicating the priority of this common time service relative to other
+     * common time services operating in the same domain.
+     * @throws android.os.RemoteException
+     */
+    public byte getMasterElectionPriority()
+    throws RemoteException {
+        throwOnDeadServer();
+        return (byte)mUtils.transactGetInt(METHOD_GET_MASTER_ELECTION_PRIORITY, -1);
+    }
+
+    /**
+     * Sets the current priority of the common time service used in the master election protocol.
+     *
+     * @param priority priority of the common time service used in the master election protocol.
+     * Lower numbers are lower priority.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setMasterElectionPriority(byte priority) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+        return mUtils.transactSetInt(METHOD_SET_MASTER_ELECTION_PRIORITY, priority);
+    }
+
+    /**
+     * Gets the IP endpoint used by the time service to participate in the master election protocol.
+     *
+     * @return an InetSocketAddress containing the IP address and UDP port being used by the
+     * system's common time service to participate in the master election protocol.
+     * @throws android.os.RemoteException
+     */
+    public InetSocketAddress getMasterElectionEndpoint()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetSockaddr(METHOD_GET_MASTER_ELECTION_ENDPOINT);
+    }
+
+    /**
+     * Sets the IP endpoint used by the common time service to participate in the master election
+     * protocol.
+     *
+     * @param ep The IP address and UDP port to be used by the common time service to participate in
+     * the master election protocol.  The supplied IP address must be either the broadcast or
+     * multicast address, unicast addresses are considered to be illegal values.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setMasterElectionEndpoint(InetSocketAddress ep) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+        return mUtils.transactSetSockaddr(METHOD_SET_MASTER_ELECTION_ENDPOINT, ep);
+    }
+
+    /**
+     * Gets the current group ID used by the common time service in the master election protocol.
+     *
+     * @return The 64-bit group ID of the common time service.
+     * @throws android.os.RemoteException
+     */
+    public long getMasterElectionGroupId()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetLong(METHOD_GET_MASTER_ELECTION_GROUP_ID, INVALID_GROUP_ID);
+    }
+
+    /**
+     * Sets the current group ID used by the common time service in the master election protocol.
+     *
+     * @param id The 64-bit group ID of the common time service.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setMasterElectionGroupId(long id) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+        return mUtils.transactSetLong(METHOD_SET_MASTER_ELECTION_GROUP_ID, id);
+    }
+
+    /**
+     * Gets the name of the network interface which the common time service attempts to bind to.
+     *
+     * @return a string with the network interface name which the common time service is bound to,
+     * or null if the service is currently unbound.  Examples of interface names are things like
+     * "eth0", or "wlan0".
+     * @throws android.os.RemoteException
+     */
+    public String getInterfaceBinding()
+    throws RemoteException {
+        throwOnDeadServer();
+
+        String ifaceName = mUtils.transactGetString(METHOD_GET_INTERFACE_BINDING, null);
+
+        if ((null != ifaceName) && (0 == ifaceName.length()))
+                return null;
+
+        return ifaceName;
+    }
+
+    /**
+     * Sets the name of the network interface which the common time service should attempt to bind
+     * to.
+     *
+     * @param ifaceName The name of the network interface ("eth0", "wlan0", etc...) wich the common
+     * time service should attempt to bind to, or null to force the common time service to unbind
+     * from the network and run in networkless mode.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setNetworkBinding(String ifaceName) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+
+        return mUtils.transactSetString(METHOD_SET_INTERFACE_BINDING,
+                                       (null == ifaceName) ? "" : ifaceName);
+    }
+
+    /**
+     * Gets the amount of time the common time service will wait between master announcements when
+     * it is the timeline master.
+     *
+     * @return The time (in milliseconds) between master announcements.
+     * @throws android.os.RemoteException
+     */
+    public int getMasterAnnounceInterval()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetInt(METHOD_GET_MASTER_ANNOUNCE_INTERVAL, -1);
+    }
+
+    /**
+     * Sets the amount of time the common time service will wait between master announcements when
+     * it is the timeline master.
+     *
+     * @param interval The time (in milliseconds) between master announcements.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setMasterAnnounceInterval(int interval) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+        return mUtils.transactSetInt(METHOD_SET_MASTER_ANNOUNCE_INTERVAL, interval);
+    }
+
+    /**
+     * Gets the amount of time the common time service will wait between time synchronization
+     * requests when it is the client of another common time service on the network.
+     *
+     * @return The time (in milliseconds) between time sync requests.
+     * @throws android.os.RemoteException
+     */
+    public int getClientSyncInterval()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetInt(METHOD_GET_CLIENT_SYNC_INTERVAL, -1);
+    }
+
+    /**
+     * Sets the amount of time the common time service will wait between time synchronization
+     * requests when it is the client of another common time service on the network.
+     *
+     * @param interval The time (in milliseconds) between time sync requests.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setClientSyncInterval(int interval) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+        return mUtils.transactSetInt(METHOD_SET_CLIENT_SYNC_INTERVAL, interval);
+    }
+
+    /**
+     * Gets the panic threshold for the estimated error level of the common time service.  When the
+     * common time service's estimated error rises above this level, the service will panic and
+     * reset, causing a discontinuity in the currently synchronized timeline.
+     *
+     * @return The threshold (in microseconds) past which the common time service will panic.
+     * @throws android.os.RemoteException
+     */
+    public int getPanicThreshold()
+    throws RemoteException {
+        throwOnDeadServer();
+        return mUtils.transactGetInt(METHOD_GET_PANIC_THRESHOLD, -1);
+    }
+
+    /**
+     * Sets the panic threshold for the estimated error level of the common time service.  When the
+     * common time service's estimated error rises above this level, the service will panic and
+     * reset, causing a discontinuity in the currently synchronized timeline.
+     *
+     * @param threshold The threshold (in microseconds) past which the common time service will
+     * panic.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR}, {@link #ERROR_BAD_VALUE} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setPanicThreshold(int threshold) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+        return mUtils.transactSetInt(METHOD_SET_PANIC_THRESHOLD, threshold);
+    }
+
+    /**
+     * Gets the current state of the common time service's auto disable flag.
+     *
+     * @return The current state of the common time service's auto disable flag.
+     * @throws android.os.RemoteException
+     */
+    public boolean getAutoDisable()
+    throws RemoteException {
+        throwOnDeadServer();
+        return (1 == mUtils.transactGetInt(METHOD_GET_AUTO_DISABLE, 1));
+    }
+
+    /**
+     * Sets the current state of the common time service's auto disable flag.  When the time
+     * service's auto disable flag is set, it will automatically cease all network activity when
+     * it has no active local clients, resuming activity the next time the service has interested
+     * local clients.  When the auto disabled flag is cleared, the common time service will continue
+     * to participate the time synchronization group even when it has no active local clients.
+     *
+     * @param autoDisable The desired state of the common time service's auto disable flag.
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int setAutoDisable(boolean autoDisable) {
+        if (checkDeadServer())
+            return ERROR_DEAD_OBJECT;
+
+        return mUtils.transactSetInt(METHOD_SET_AUTO_DISABLE, autoDisable ? 1 : 0);
+    }
+
+    /**
+     * At startup, the time service enters the initial state and remains there until it is given a
+     * network interface to bind to.  Common time will be unavailable to clients of the common time
+     * service until the service joins a network (even an empty network).  Devices may use the
+     * {@link #forceNetworklessMasterMode()} method to force a time service in the INITIAL state
+     * with no network configuration to assume MASTER status for a brand new timeline in order to
+     * allow clients of the common time service to operate, even though the device is isolated and
+     * not on any network.  When a networkless master does join a network, it will defer to any
+     * masters already on the network, or continue to maintain the timeline it made up during its
+     * networkless state if no other masters are detected.  Attempting to force a client into master
+     * mode while it is actively bound to a network will fail with the status code {@link #ERROR}
+     *
+     * @return {@link #SUCCESS} in case of success,
+     * {@link #ERROR} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+     */
+    public int forceNetworklessMasterMode() {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+
+        try {
+            data.writeInterfaceToken(mInterfaceDesc);
+            mRemote.transact(METHOD_FORCE_NETWORKLESS_MASTER_MODE, data, reply, 0);
+
+            return reply.readInt();
+        }
+        catch (RemoteException e) {
+            return ERROR_DEAD_OBJECT;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+    }
+
+    /**
+     * The OnServerDiedListener interface defines a method called by the
+     * {@link android.os.CommonTimeConfig} instance to indicate that the connection to the native
+     * media server has been broken and that the {@link android.os.CommonTimeConfig} instance will
+     * need to be released and re-created.  The client application can implement this interface and
+     * register the listener with the {@link #setServerDiedListener(OnServerDiedListener)} method.
+     */
+    public interface OnServerDiedListener  {
+        /**
+         * Method called when the native common time service has died.  <p>If the native common time
+         * service encounters a fatal error and needs to restart, the binder connection from the
+         * {@link android.os.CommonTimeConfig} instance to the common time service will be broken.
+         */
+        void onServerDied();
+    }
+
+    /**
+     * Registers an OnServerDiedListener interface.
+     * <p>Call this method with a null listener to stop receiving server death notifications.
+     */
+    public void setServerDiedListener(OnServerDiedListener listener) {
+        synchronized (mListenerLock) {
+            mServerDiedListener = listener;
+        }
+    }
+
+    protected void finalize() throws Throwable { release(); }
+
+    private boolean checkDeadServer() {
+        return ((null == mRemote) || (null == mUtils));
+    }
+
+    private void throwOnDeadServer() throws RemoteException {
+        if (checkDeadServer())
+            throw new RemoteException();
+    }
+
+    private final Object mListenerLock = new Object();
+    private OnServerDiedListener mServerDiedListener = null;
+
+    private IBinder mRemote = null;
+    private String mInterfaceDesc = "";
+    private CommonTimeUtils mUtils;
+
+    private IBinder.DeathRecipient mDeathHandler = new IBinder.DeathRecipient() {
+        public void binderDied() {
+            synchronized (mListenerLock) {
+                if (null != mServerDiedListener)
+                    mServerDiedListener.onServerDied();
+            }
+        }
+    };
+
+    private static final int METHOD_GET_MASTER_ELECTION_PRIORITY = IBinder.FIRST_CALL_TRANSACTION;
+    private static final int METHOD_SET_MASTER_ELECTION_PRIORITY = METHOD_GET_MASTER_ELECTION_PRIORITY + 1;
+    private static final int METHOD_GET_MASTER_ELECTION_ENDPOINT = METHOD_SET_MASTER_ELECTION_PRIORITY + 1;
+    private static final int METHOD_SET_MASTER_ELECTION_ENDPOINT = METHOD_GET_MASTER_ELECTION_ENDPOINT + 1;
+    private static final int METHOD_GET_MASTER_ELECTION_GROUP_ID = METHOD_SET_MASTER_ELECTION_ENDPOINT + 1;
+    private static final int METHOD_SET_MASTER_ELECTION_GROUP_ID = METHOD_GET_MASTER_ELECTION_GROUP_ID + 1;
+    private static final int METHOD_GET_INTERFACE_BINDING = METHOD_SET_MASTER_ELECTION_GROUP_ID + 1;
+    private static final int METHOD_SET_INTERFACE_BINDING = METHOD_GET_INTERFACE_BINDING + 1;
+    private static final int METHOD_GET_MASTER_ANNOUNCE_INTERVAL = METHOD_SET_INTERFACE_BINDING + 1;
+    private static final int METHOD_SET_MASTER_ANNOUNCE_INTERVAL = METHOD_GET_MASTER_ANNOUNCE_INTERVAL + 1;
+    private static final int METHOD_GET_CLIENT_SYNC_INTERVAL = METHOD_SET_MASTER_ANNOUNCE_INTERVAL + 1;
+    private static final int METHOD_SET_CLIENT_SYNC_INTERVAL = METHOD_GET_CLIENT_SYNC_INTERVAL + 1;
+    private static final int METHOD_GET_PANIC_THRESHOLD = METHOD_SET_CLIENT_SYNC_INTERVAL + 1;
+    private static final int METHOD_SET_PANIC_THRESHOLD = METHOD_GET_PANIC_THRESHOLD + 1;
+    private static final int METHOD_GET_AUTO_DISABLE = METHOD_SET_PANIC_THRESHOLD + 1;
+    private static final int METHOD_SET_AUTO_DISABLE = METHOD_GET_AUTO_DISABLE + 1;
+    private static final int METHOD_FORCE_NETWORKLESS_MASTER_MODE = METHOD_SET_AUTO_DISABLE + 1;
+}
diff --git a/core/java/android/os/CommonTimeUtils.java b/core/java/android/os/CommonTimeUtils.java
new file mode 100644
index 0000000..9081ee4
--- /dev/null
+++ b/core/java/android/os/CommonTimeUtils.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.os;
+
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetSocketAddress;
+import static libcore.io.OsConstants.*;
+
+class CommonTimeUtils {
+    /**
+     * Successful operation.
+     */
+    public static final int SUCCESS = 0;
+    /**
+     * Unspecified error.
+     */
+    public static final int ERROR = -1;
+    /**
+     * Operation failed due to bad parameter value.
+     */
+    public static final int ERROR_BAD_VALUE = -4;
+    /**
+     * Operation failed due to dead remote object.
+     */
+    public static final int ERROR_DEAD_OBJECT = -7;
+
+    public CommonTimeUtils(IBinder remote, String interfaceDesc) {
+        mRemote = remote;
+        mInterfaceDesc = interfaceDesc;
+    }
+
+    public int transactGetInt(int method_code, int error_ret_val)
+    throws RemoteException {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+        int ret_val;
+
+        try {
+            int res;
+            data.writeInterfaceToken(mInterfaceDesc);
+            mRemote.transact(method_code, data, reply, 0);
+
+            res = reply.readInt();
+            ret_val = (0 == res) ? reply.readInt() : error_ret_val;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+
+        return ret_val;
+    }
+
+    public int transactSetInt(int method_code, int val) {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+
+        try {
+            data.writeInterfaceToken(mInterfaceDesc);
+            data.writeInt(val);
+            mRemote.transact(method_code, data, reply, 0);
+
+            return reply.readInt();
+        }
+        catch (RemoteException e) {
+            return ERROR_DEAD_OBJECT;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+    }
+
+    public long transactGetLong(int method_code, long error_ret_val)
+    throws RemoteException {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+        long ret_val;
+
+        try {
+            int res;
+            data.writeInterfaceToken(mInterfaceDesc);
+            mRemote.transact(method_code, data, reply, 0);
+
+            res = reply.readInt();
+            ret_val = (0 == res) ? reply.readLong() : error_ret_val;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+
+        return ret_val;
+    }
+
+    public int transactSetLong(int method_code, long val) {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+
+        try {
+            data.writeInterfaceToken(mInterfaceDesc);
+            data.writeLong(val);
+            mRemote.transact(method_code, data, reply, 0);
+
+            return reply.readInt();
+        }
+        catch (RemoteException e) {
+            return ERROR_DEAD_OBJECT;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+    }
+
+    public String transactGetString(int method_code, String error_ret_val)
+    throws RemoteException {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+        String ret_val;
+
+        try {
+            int res;
+            data.writeInterfaceToken(mInterfaceDesc);
+            mRemote.transact(method_code, data, reply, 0);
+
+            res = reply.readInt();
+            ret_val = (0 == res) ? reply.readString() : error_ret_val;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+
+        return ret_val;
+    }
+
+    public int transactSetString(int method_code, String val) {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+
+        try {
+            data.writeInterfaceToken(mInterfaceDesc);
+            data.writeString(val);
+            mRemote.transact(method_code, data, reply, 0);
+
+            return reply.readInt();
+        }
+        catch (RemoteException e) {
+            return ERROR_DEAD_OBJECT;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+    }
+
+    public InetSocketAddress transactGetSockaddr(int method_code)
+    throws RemoteException {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+        InetSocketAddress ret_val = null;
+
+        try {
+            int res;
+            data.writeInterfaceToken(mInterfaceDesc);
+            mRemote.transact(method_code, data, reply, 0);
+
+            res = reply.readInt();
+            if (0 == res) {
+                int type;
+                int port = 0;
+                String addrStr = null;
+
+                type = reply.readInt();
+
+                if (AF_INET == type) {
+                    int addr = reply.readInt();
+                    port = reply.readInt();
+                    addrStr = String.format("%d.%d.%d.%d", (addr >> 24) & 0xFF,
+                                                           (addr >> 16) & 0xFF,
+                                                           (addr >>  8) & 0xFF,
+                                                            addr        & 0xFF);
+                } else if (AF_INET6 == type) {
+                    int addr1 = reply.readInt();
+                    int addr2 = reply.readInt();
+                    int addr3 = reply.readInt();
+                    int addr4 = reply.readInt();
+
+                    port = reply.readInt();
+
+                    int flowinfo = reply.readInt();
+                    int scope_id = reply.readInt();
+
+                    addrStr = String.format("[%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X]",
+                                            (addr1 >> 16) & 0xFFFF, addr1 & 0xFFFF,
+                                            (addr2 >> 16) & 0xFFFF, addr2 & 0xFFFF,
+                                            (addr3 >> 16) & 0xFFFF, addr3 & 0xFFFF,
+                                            (addr4 >> 16) & 0xFFFF, addr4 & 0xFFFF);
+                }
+
+                if (null != addrStr) {
+                    ret_val = new InetSocketAddress(addrStr, port);
+                }
+            }
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+
+        return ret_val;
+    }
+
+    public int transactSetSockaddr(int method_code, InetSocketAddress addr) {
+        android.os.Parcel data  = android.os.Parcel.obtain();
+        android.os.Parcel reply = android.os.Parcel.obtain();
+        int ret_val = ERROR;
+
+        try {
+            data.writeInterfaceToken(mInterfaceDesc);
+
+            if (null == addr) {
+                data.writeInt(0);
+            } else {
+                data.writeInt(1);
+                final InetAddress a = addr.getAddress();
+                final byte[]      b = a.getAddress();
+                final int         p = addr.getPort();
+
+                if (a instanceof Inet4Address) {
+                    int v4addr = (((int)b[0] & 0xFF) << 24) |
+                                 (((int)b[1] & 0xFF) << 16) |
+                                 (((int)b[2] & 0xFF) << 8) |
+                                  ((int)b[3] & 0xFF);
+
+                    data.writeInt(AF_INET);
+                    data.writeInt(v4addr);
+                    data.writeInt(p);
+                } else
+                if (a instanceof Inet6Address) {
+                    int i;
+                    Inet6Address v6 = (Inet6Address)a;
+                    data.writeInt(AF_INET6);
+                    for (i = 0; i < 4; ++i) {
+                        int aword = (((int)b[(i*4) + 0] & 0xFF) << 24) |
+                                    (((int)b[(i*4) + 1] & 0xFF) << 16) |
+                                    (((int)b[(i*4) + 2] & 0xFF) << 8) |
+                                     ((int)b[(i*4) + 3] & 0xFF);
+                        data.writeInt(aword);
+                    }
+                    data.writeInt(p);
+                    data.writeInt(0);   // flow info
+                    data.writeInt(v6.getScopeId());
+                } else {
+                    return ERROR_BAD_VALUE;
+                }
+            }
+
+            mRemote.transact(method_code, data, reply, 0);
+            ret_val = reply.readInt();
+        }
+        catch (RemoteException e) {
+            ret_val = ERROR_DEAD_OBJECT;
+        }
+        finally {
+            reply.recycle();
+            data.recycle();
+        }
+
+        return ret_val;
+    }
+
+    private IBinder mRemote;
+    private String mInterfaceDesc;
+};
diff --git a/core/java/android/os/Handler.java b/core/java/android/os/Handler.java
index af2fa9b..610b3550 100644
--- a/core/java/android/os/Handler.java
+++ b/core/java/android/os/Handler.java
@@ -513,7 +513,7 @@
      * message queue.
      */
     public final void removeMessages(int what) {
-        mQueue.removeMessages(this, what, null, true);
+        mQueue.removeMessages(this, what, null);
     }
 
     /**
@@ -522,7 +522,7 @@
      * all messages will be removed.
      */
     public final void removeMessages(int what, Object object) {
-        mQueue.removeMessages(this, what, object, true);
+        mQueue.removeMessages(this, what, object);
     }
 
     /**
@@ -539,7 +539,7 @@
      * the message queue.
      */
     public final boolean hasMessages(int what) {
-        return mQueue.removeMessages(this, what, null, false);
+        return mQueue.hasMessages(this, what, null);
     }
 
     /**
@@ -547,7 +547,7 @@
      * whose obj is 'object' in the message queue.
      */
     public final boolean hasMessages(int what, Object object) {
-        return mQueue.removeMessages(this, what, object, false);
+        return mQueue.hasMessages(this, what, object);
     }
 
     // if we can get rid of this method, the handler need not remember its loop
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index 5607f7f..a06aadb6 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -55,13 +55,13 @@
 
     // sThreadLocal.get() will return null unless you've called prepare().
     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
+    private static Looper sMainLooper;  // guarded by Looper.class
 
     final MessageQueue mQueue;
     final Thread mThread;
     volatile boolean mRun;
 
-    private Printer mLogging = null;
-    private static Looper mMainLooper = null;  // guarded by Looper.class
+    private Printer mLogging;
 
      /** Initialize the current thread as a looper.
       * This gives you a chance to create handlers that then reference
@@ -70,10 +70,14 @@
       * {@link #quit()}.
       */
     public static void prepare() {
+        prepare(true);
+    }
+
+    private static void prepare(boolean quitAllowed) {
         if (sThreadLocal.get() != null) {
             throw new RuntimeException("Only one Looper may be created per thread");
         }
-        sThreadLocal.set(new Looper());
+        sThreadLocal.set(new Looper(quitAllowed));
     }
 
     /**
@@ -83,19 +87,21 @@
      * to call this function yourself.  See also: {@link #prepare()}
      */
     public static void prepareMainLooper() {
-        prepare();
-        setMainLooper(myLooper());
-        myLooper().mQueue.mQuitAllowed = false;
-    }
-
-    private synchronized static void setMainLooper(Looper looper) {
-        mMainLooper = looper;
+        prepare(false);
+        synchronized (Looper.class) {
+            if (sMainLooper != null) {
+                throw new IllegalStateException("The main Looper has already been prepared.");
+            }
+            sMainLooper = myLooper();
+        }
     }
 
     /** Returns the application's main looper, which lives in the main thread of the application.
      */
-    public synchronized static Looper getMainLooper() {
-        return mMainLooper;
+    public static Looper getMainLooper() {
+        synchronized (Looper.class) {
+            return sMainLooper;
+        }
     }
 
     /**
@@ -103,63 +109,61 @@
      * {@link #quit()} to end the loop.
      */
     public static void loop() {
-        Looper me = myLooper();
+        final Looper me = myLooper();
         if (me == null) {
             throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
         }
-        MessageQueue queue = me.mQueue;
-        
+        final MessageQueue queue = me.mQueue;
+
         // Make sure the identity of this thread is that of the local process,
         // and keep track of what that identity token actually is.
         Binder.clearCallingIdentity();
         final long ident = Binder.clearCallingIdentity();
-        
-        while (true) {
+
+        for (;;) {
             Message msg = queue.next(); // might block
-            if (msg != null) {
-                if (msg.target == null) {
-                    // No target is a magic identifier for the quit message.
-                    return;
-                }
-
-                long wallStart = 0;
-                long threadStart = 0;
-
-                // This must be in a local variable, in case a UI event sets the logger
-                Printer logging = me.mLogging;
-                if (logging != null) {
-                    logging.println(">>>>> Dispatching to " + msg.target + " " +
-                            msg.callback + ": " + msg.what);
-                    wallStart = SystemClock.currentTimeMicro();
-                    threadStart = SystemClock.currentThreadTimeMicro();
-                }
-
-                msg.target.dispatchMessage(msg);
-
-                if (logging != null) {
-                    long wallTime = SystemClock.currentTimeMicro() - wallStart;
-                    long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
-
-                    logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
-                    if (logging instanceof Profiler) {
-                        ((Profiler) logging).profile(msg, wallStart, wallTime,
-                                threadStart, threadTime);
-                    }
-                }
-
-                // Make sure that during the course of dispatching the
-                // identity of the thread wasn't corrupted.
-                final long newIdent = Binder.clearCallingIdentity();
-                if (ident != newIdent) {
-                    Log.wtf(TAG, "Thread identity changed from 0x"
-                            + Long.toHexString(ident) + " to 0x"
-                            + Long.toHexString(newIdent) + " while dispatching to "
-                            + msg.target.getClass().getName() + " "
-                            + msg.callback + " what=" + msg.what);
-                }
-                
-                msg.recycle();
+            if (msg == null) {
+                // No message indicates that the message queue is quitting.
+                return;
             }
+
+            long wallStart = 0;
+            long threadStart = 0;
+
+            // This must be in a local variable, in case a UI event sets the logger
+            Printer logging = me.mLogging;
+            if (logging != null) {
+                logging.println(">>>>> Dispatching to " + msg.target + " " +
+                        msg.callback + ": " + msg.what);
+                wallStart = SystemClock.currentTimeMicro();
+                threadStart = SystemClock.currentThreadTimeMicro();
+            }
+
+            msg.target.dispatchMessage(msg);
+
+            if (logging != null) {
+                long wallTime = SystemClock.currentTimeMicro() - wallStart;
+                long threadTime = SystemClock.currentThreadTimeMicro() - threadStart;
+
+                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
+                if (logging instanceof Profiler) {
+                    ((Profiler) logging).profile(msg, wallStart, wallTime,
+                            threadStart, threadTime);
+                }
+            }
+
+            // Make sure that during the course of dispatching the
+            // identity of the thread wasn't corrupted.
+            final long newIdent = Binder.clearCallingIdentity();
+            if (ident != newIdent) {
+                Log.wtf(TAG, "Thread identity changed from 0x"
+                        + Long.toHexString(ident) + " to 0x"
+                        + Long.toHexString(newIdent) + " while dispatching to "
+                        + msg.target.getClass().getName() + " "
+                        + msg.callback + " what=" + msg.what);
+            }
+
+            msg.recycle();
         }
     }
 
@@ -193,18 +197,61 @@
         return myLooper().mQueue;
     }
 
-    private Looper() {
-        mQueue = new MessageQueue();
+    private Looper(boolean quitAllowed) {
+        mQueue = new MessageQueue(quitAllowed);
         mRun = true;
         mThread = Thread.currentThread();
     }
 
+    /**
+     * Quits the looper.
+     *
+     * Causes the {@link #loop} method to terminate as soon as possible.
+     */
     public void quit() {
-        Message msg = Message.obtain();
-        // NOTE: By enqueueing directly into the message queue, the
-        // message is left with a null target.  This is how we know it is
-        // a quit message.
-        mQueue.enqueueMessage(msg, 0);
+        mQueue.quit();
+    }
+
+    /**
+     * Posts a synchronization barrier to the Looper's message queue.
+     *
+     * Message processing occurs as usual until the message queue encounters the
+     * synchronization barrier that has been posted.  When the barrier is encountered,
+     * later synchronous messages in the queue are stalled (prevented from being executed)
+     * until the barrier is released by calling {@link #removeSyncBarrier} and specifying
+     * the token that identifies the synchronization barrier.
+     *
+     * This method is used to immediately postpone execution of all subsequently posted
+     * synchronous messages until a condition is met that releases the barrier.
+     * Asynchronous messages (see {@link Message#isAsynchronous} are exempt from the barrier
+     * and continue to be processed as usual.
+     *
+     * This call must be always matched by a call to {@link #removeSyncBarrier} with
+     * the same token to ensure that the message queue resumes normal operation.
+     * Otherwise the application will probably hang!
+     *
+     * @return A token that uniquely identifies the barrier.  This token must be
+     * passed to {@link #removeSyncBarrier} to release the barrier.
+     *
+     * @hide
+     */
+    public final int postSyncBarrier() {
+        return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
+    }
+
+
+    /**
+     * Removes a synchronization barrier.
+     *
+     * @param token The synchronization barrier token that was returned by
+     * {@link #postSyncBarrier}.
+     *
+     * @throws IllegalStateException if the barrier was not found.
+     *
+     * @hide
+     */
+    public final void removeSyncBarrier(int token) {
+        mQueue.removeSyncBarrier(token);
     }
 
     /**
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index 11dc124..64027ef 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -30,21 +30,24 @@
  * {@link Looper#myQueue() Looper.myQueue()}.
  */
 public class MessageQueue {
+    // True if the message queue can be quit.
+    private final boolean mQuitAllowed;
+
+    @SuppressWarnings("unused")
+    private int mPtr; // used by native code
+
     Message mMessages;
     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
     private IdleHandler[] mPendingIdleHandlers;
     private boolean mQuiting;
-    boolean mQuitAllowed = true;
 
     // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.
     private boolean mBlocked;
 
-    // Indicates the barrier nesting level.
-    private int mBarrierNestCount;
+    // The next barrier token.
+    // Barriers are indicated by messages with a null target whose arg1 field carries the token.
+    private int mNextBarrierToken;
 
-    @SuppressWarnings("unused")
-    private int mPtr; // used by native code
-    
     private native void nativeInit();
     private native void nativeDestroy();
     private native void nativePollOnce(int ptr, int timeoutMillis);
@@ -97,56 +100,11 @@
         }
     }
 
-    /**
-     * Acquires a synchronization barrier.
-     *
-     * While a synchronization barrier is active, only asynchronous messages are
-     * permitted to execute.  Synchronous messages are retained but are not executed
-     * until the synchronization barrier is released.
-     *
-     * This method is used to immediately postpone execution of all synchronous messages
-     * until a condition is met that releases the barrier.  Asynchronous messages are
-     * exempt from the barrier and continue to be executed as usual.
-     *
-     * This call nests and must be matched by an equal number of calls to
-     * {@link #releaseSyncBarrier}.
-     *
-     * @hide
-     */
-    public final void acquireSyncBarrier() {
-        synchronized (this) {
-            mBarrierNestCount += 1;
-        }
-    }
-
-    /**
-     * Releases a synchronization barrier.
-     *
-     * This class undoes one invocation of {@link #acquireSyncBarrier}.
-     *
-     * @throws IllegalStateException if the barrier is not acquired.
-     *
-     * @hide
-     */
-    public final void releaseSyncBarrier() {
-        synchronized (this) {
-            if (mBarrierNestCount == 0) {
-                throw new IllegalStateException("The message queue synchronization barrier "
-                        + "has not been acquired.");
-            }
-
-            mBarrierNestCount -= 1;
-            if (!mBlocked || mMessages == null) {
-                return;
-            }
-        }
-        nativeWake(mPtr);
-    }
-
-    MessageQueue() {
+    MessageQueue(boolean quitAllowed) {
+        mQuitAllowed = quitAllowed;
         nativeInit();
     }
-    
+
     @Override
     protected void finalize() throws Throwable {
         try {
@@ -167,26 +125,26 @@
             nativePollOnce(mPtr, nextPollTimeoutMillis);
 
             synchronized (this) {
+                if (mQuiting) {
+                    return null;
+                }
+
                 // Try to retrieve the next message.  Return if found.
                 final long now = SystemClock.uptimeMillis();
-
                 Message prevMsg = null;
                 Message msg = mMessages;
-                for (;;) {
-                    if (msg == null) {
-                        // No more messages.
-                        nextPollTimeoutMillis = -1;
-                        break;
-                    }
-
-                    final long when = msg.when;
-                    if (now < when) {
+                if (msg != null && msg.target == null) {
+                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
+                    do {
+                        prevMsg = msg;
+                        msg = msg.next;
+                    } while (msg != null && !msg.isAsynchronous());
+                }
+                if (msg != null) {
+                    if (now < msg.when) {
                         // Next message is not ready.  Set a timeout to wake up when it is ready.
-                        nextPollTimeoutMillis = (int) Math.min(when - now, Integer.MAX_VALUE);
-                        break;
-                    }
-
-                    if (mBarrierNestCount == 0 || msg.isAsynchronous()) {
+                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
+                    } else {
                         // Got a message.
                         mBlocked = false;
                         if (prevMsg != null) {
@@ -199,16 +157,16 @@
                         msg.markInUse();
                         return msg;
                     }
-
-                    // We have a message that we could return except that it is
-                    // blocked by the sync barrier.  In particular, this means that
-                    // we are not idle yet, so we do not want to run the idle handlers.
-                    prevMsg = msg;
-                    msg = msg.next;
+                } else {
+                    // No more messages.
+                    nextPollTimeoutMillis = -1;
                 }
 
                 // If first time idle, then get the number of idlers to run.
-                if (pendingIdleHandlerCount < 0 && msg == mMessages) {
+                // Idle handles only run if the queue is empty or if the first message
+                // in the queue (possibly a barrier) is due to be handled in the future.
+                if (pendingIdleHandlerCount < 0
+                        && (mMessages == null || now < mMessages.when)) {
                     pendingIdleHandlerCount = mIdleHandlers.size();
                 }
                 if (pendingIdleHandlerCount <= 0) {
@@ -252,27 +210,94 @@
         }
     }
 
+    final void quit() {
+        if (!mQuitAllowed) {
+            throw new RuntimeException("Main thread not allowed to quit.");
+        }
+
+        synchronized (this) {
+            if (mQuiting) {
+                return;
+            }
+            mQuiting = true;
+        }
+        nativeWake(mPtr);
+    }
+
+    final int enqueueSyncBarrier(long when) {
+        // Enqueue a new sync barrier token.
+        // We don't need to wake the queue because the purpose of a barrier is to stall it.
+        synchronized (this) {
+            final int token = mNextBarrierToken++;
+            final Message msg = Message.obtain();
+            msg.arg1 = token;
+
+            Message prev = null;
+            Message p = mMessages;
+            if (when != 0) {
+                while (p != null && p.when <= when) {
+                    prev = p;
+                    p = p.next;
+                }
+            }
+            if (prev != null) { // invariant: p == prev.next
+                msg.next = p;
+                prev.next = msg;
+            } else {
+                msg.next = p;
+                mMessages = msg;
+            }
+            return token;
+        }
+    }
+
+    final void removeSyncBarrier(int token) {
+        // Remove a sync barrier token from the queue.
+        // If the queue is no longer stalled by a barrier then wake it.
+        final boolean needWake;
+        synchronized (this) {
+            Message prev = null;
+            Message p = mMessages;
+            while (p != null && (p.target != null || p.arg1 != token)) {
+                prev = p;
+                p = p.next;
+            }
+            if (p == null) {
+                throw new IllegalStateException("The specified message queue synchronization "
+                        + " barrier token has not been posted or has already been removed.");
+            }
+            if (prev != null) {
+                prev.next = p.next;
+                needWake = false;
+            } else {
+                mMessages = p.next;
+                needWake = mMessages == null || mMessages.target != null;
+            }
+            p.recycle();
+        }
+        if (needWake) {
+            nativeWake(mPtr);
+        }
+    }
+
     final boolean enqueueMessage(Message msg, long when) {
         if (msg.isInUse()) {
-            throw new AndroidRuntimeException(msg
-                    + " This message is already in use.");
+            throw new AndroidRuntimeException(msg + " This message is already in use.");
         }
-        if (msg.target == null && !mQuitAllowed) {
-            throw new RuntimeException("Main thread not allowed to quit");
+        if (msg.target == null) {
+            throw new AndroidRuntimeException("Message must have a target.");
         }
-        final boolean needWake;
+
+        boolean needWake;
         synchronized (this) {
             if (mQuiting) {
                 RuntimeException e = new RuntimeException(
-                    msg.target + " sending message to a Handler on a dead thread");
+                        msg.target + " sending message to a Handler on a dead thread");
                 Log.w("MessageQueue", e.getMessage(), e);
                 return false;
-            } else if (msg.target == null) {
-                mQuiting = true;
             }
 
             msg.when = when;
-            //Log.d("MessageQueue", "Enqueing: " + msg);
             Message p = mMessages;
             if (p == null || when == 0 || when < p.when) {
                 // New head, wake up the event queue if blocked.
@@ -281,18 +306,22 @@
                 needWake = mBlocked;
             } else {
                 // Inserted within the middle of the queue.  Usually we don't have to wake
-                // up the event queue unless the message is asynchronous and it might be
-                // possible for it to be returned out of sequence relative to an earlier
-                // synchronous message at the head of the queue.
-                Message prev = null;
-                while (p != null && p.when <= when) {
+                // up the event queue unless there is a barrier at the head of the queue
+                // and the message is the earliest asynchronous message in the queue.
+                needWake = mBlocked && p.target == null && msg.isAsynchronous();
+                Message prev;
+                for (;;) {
                     prev = p;
                     p = p.next;
+                    if (p == null || when < p.when) {
+                        break;
+                    }
+                    if (needWake && p.isAsynchronous()) {
+                        needWake = false;
+                    }
                 }
-                msg.next = prev.next;
+                msg.next = p; // invariant: p == prev.next
                 prev.next = msg;
-                needWake = mBlocked && mBarrierNestCount != 0 && msg.isAsynchronous()
-                        && !mMessages.isAsynchronous();
             }
         }
         if (needWake) {
@@ -301,17 +330,34 @@
         return true;
     }
 
-    final boolean removeMessages(Handler h, int what, Object object,
-            boolean doRemove) {
+    final boolean hasMessages(Handler h, int what, Object object) {
+        if (h == null) {
+            return false;
+        }
+
         synchronized (this) {
             Message p = mMessages;
-            boolean found = false;
+            while (p != null) {
+                if (p.target == h && p.what == what && (object == null || p.obj == object)) {
+                    return true;
+                }
+                p = p.next;
+            }
+            return false;
+        }
+    }
+
+    final void removeMessages(Handler h, int what, Object object) {
+        if (h == null) {
+            return;
+        }
+
+        synchronized (this) {
+            Message p = mMessages;
 
             // Remove all messages at front.
             while (p != null && p.target == h && p.what == what
                    && (object == null || p.obj == object)) {
-                if (!doRemove) return true;
-                found = true;
                 Message n = p.next;
                 mMessages = n;
                 p.recycle();
@@ -324,8 +370,6 @@
                 if (n != null) {
                     if (n.target == h && n.what == what
                         && (object == null || n.obj == object)) {
-                        if (!doRemove) return true;
-                        found = true;
                         Message nn = n.next;
                         n.recycle();
                         p.next = nn;
@@ -334,13 +378,11 @@
                 }
                 p = n;
             }
-            
-            return found;
         }
     }
 
     final void removeMessages(Handler h, Runnable r, Object object) {
-        if (r == null) {
+        if (h == null || r == null) {
             return;
         }
 
@@ -374,6 +416,10 @@
     }
 
     final void removeCallbacksAndMessages(Handler h, Object object) {
+        if (h == null) {
+            return;
+        }
+
         synchronized (this) {
             Message p = mMessages;
 
@@ -401,16 +447,4 @@
             }
         }
     }
-
-    /*
-    private void dumpQueue_l()
-    {
-        Message p = mMessages;
-        System.out.println(this + "  queue is:");
-        while (p != null) {
-            System.out.println("            " + p);
-            p = p.next;
-        }
-    }
-    */
 }
diff --git a/core/java/android/os/Power.java b/core/java/android/os/Power.java
index 5a79215..58df940 100644
--- a/core/java/android/os/Power.java
+++ b/core/java/android/os/Power.java
@@ -104,4 +104,6 @@
     }
 
     private static native void rebootNative(String reason) throws IOException ;
+
+    public static native int powerInitNative();
 }
diff --git a/core/java/android/service/textservice/SpellCheckerService.java b/core/java/android/service/textservice/SpellCheckerService.java
index 2b8a458..cac449d 100644
--- a/core/java/android/service/textservice/SpellCheckerService.java
+++ b/core/java/android/service/textservice/SpellCheckerService.java
@@ -27,6 +27,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.textservice.SentenceSuggestionsInfo;
 import android.view.textservice.SuggestionsInfo;
 import android.view.textservice.TextInfo;
 
@@ -140,19 +141,21 @@
 
         /**
          * @hide
-         * The default implementation returns an array of SuggestionsInfo by simply calling
+         * The default implementation returns an array of SentenceSuggestionsInfo by simply calling
          * onGetSuggestions().
          * When you override this method, make sure that suggestionsLimit is applied to suggestions
          * that share the same start position and length.
          */
-        public SuggestionsInfo[] onGetSuggestionsMultipleForSentence(TextInfo[] textInfos,
+        public SentenceSuggestionsInfo[] onGetSentenceSuggestionsMultiple(TextInfo[] textInfos,
                 int suggestionsLimit) {
             final int length = textInfos.length;
-            final SuggestionsInfo[] retval = new SuggestionsInfo[length];
+            final SentenceSuggestionsInfo[] retval = new SentenceSuggestionsInfo[length];
             for (int i = 0; i < length; ++i) {
-                retval[i] = onGetSuggestions(textInfos[i], suggestionsLimit);
-                retval[i].setCookieAndSequence(
-                        textInfos[i].getCookie(), textInfos[i].getSequence());
+                final SuggestionsInfo si = onGetSuggestions(textInfos[i], suggestionsLimit);
+                si.setCookieAndSequence(textInfos[i].getCookie(), textInfos[i].getSequence());
+                final int N = textInfos[i].getText().length();
+                retval[i] = new SentenceSuggestionsInfo(
+                        new SuggestionsInfo[] {si}, new int[]{0}, new int[]{N});
             }
             return retval;
         }
@@ -220,11 +223,10 @@
         }
 
         @Override
-        public void onGetSuggestionsMultipleForSentence(
-                TextInfo[] textInfos, int suggestionsLimit) {
+        public void onGetSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) {
             try {
-                mListener.onGetSuggestionsForSentence(
-                        mSession.onGetSuggestionsMultipleForSentence(textInfos, suggestionsLimit));
+                mListener.onGetSentenceSuggestions(
+                        mSession.onGetSentenceSuggestionsMultiple(textInfos, suggestionsLimit));
             } catch (RemoteException e) {
             }
         }
diff --git a/core/java/android/view/AccessibilityNodeInfoCache.java b/core/java/android/view/AccessibilityNodeInfoCache.java
index 244a491..84b510d 100644
--- a/core/java/android/view/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/AccessibilityNodeInfoCache.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.os.Process;
+import android.util.Log;
 import android.util.LongSparseArray;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
@@ -30,7 +32,11 @@
  */
 public class AccessibilityNodeInfoCache {
 
-    private final boolean ENABLED = true;
+    private static final String LOG_TAG = AccessibilityNodeInfoCache.class.getSimpleName();
+
+    private static final boolean ENABLED = true;
+
+    private static final boolean DEBUG = false;
 
     /**
      * @return A new <strong>not synchronized</strong> AccessibilityNodeInfoCache.
@@ -95,6 +101,7 @@
     public void onAccessibilityEvent(AccessibilityEvent event) {
         final int eventType = event.getEventType();
         switch (eventType) {
+            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
             case AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED:
             case AccessibilityEvent.TYPE_VIEW_SCROLLED:
                 clear();
@@ -117,7 +124,14 @@
      */
     public AccessibilityNodeInfo get(long accessibilityNodeId) {
         if (ENABLED) {
-            return mCacheImpl.get(accessibilityNodeId);
+            if (DEBUG) {
+                AccessibilityNodeInfo info = mCacheImpl.get(accessibilityNodeId);
+                Log.i(LOG_TAG, "Process: " + Process.myPid() +
+                        " get(" + accessibilityNodeId + ") = " + info);
+                return info;
+            } else {
+                return mCacheImpl.get(accessibilityNodeId);
+            }
         } else {
             return null;
         }
@@ -131,6 +145,10 @@
      */
     public void put(long accessibilityNodeId, AccessibilityNodeInfo info) {
         if (ENABLED) {
+            if (DEBUG) {
+                Log.i(LOG_TAG, "Process: " + Process.myPid()
+                        + " put(" + accessibilityNodeId + ", " + info + ")");
+            }
             mCacheImpl.put(accessibilityNodeId, info);
         }
     }
@@ -156,6 +174,10 @@
      */
     public void remove(long accessibilityNodeId) {
         if (ENABLED) {
+            if (DEBUG) {
+                Log.i(LOG_TAG,  "Process: " + Process.myPid()
+                        + " remove(" + accessibilityNodeId + ")");
+            }
             mCacheImpl.remove(accessibilityNodeId);
         }
     }
@@ -165,6 +187,9 @@
      */
     public void clear() {
         if (ENABLED) {
+            if (DEBUG) {
+                Log.i(LOG_TAG,  "Process: " + Process.myPid() + "clear()");
+            }
             mCacheImpl.clear();
         }
     }
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index a74b737..42c3913 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -235,8 +235,9 @@
                 if (isRunningOnLooperThreadLocked()) {
                     doScheduleVsyncLocked();
                 } else {
-                    mHandler.sendMessageAtFrontOfQueue(
-                            mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC));
+                    Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
+                    msg.setAsynchronous(true);
+                    mHandler.sendMessageAtFrontOfQueue(msg);
                 }
             } else {
                 final long now = SystemClock.uptimeMillis();
@@ -244,7 +245,9 @@
                 if (DEBUG) {
                     Log.d(TAG, "Scheduling animation in " + (nextAnimationTime - now) + " ms.");
                 }
-                mHandler.sendEmptyMessageAtTime(MSG_DO_ANIMATION, nextAnimationTime);
+                Message msg = mHandler.obtainMessage(MSG_DO_ANIMATION);
+                msg.setAsynchronous(true);
+                mHandler.sendMessageAtTime(msg, nextAnimationTime);
             }
         }
     }
@@ -258,7 +261,9 @@
                 if (DEBUG) {
                     Log.d(TAG, "Scheduling draw immediately.");
                 }
-                mHandler.sendEmptyMessage(MSG_DO_DRAW);
+                Message msg = mHandler.obtainMessage(MSG_DO_DRAW);
+                msg.setAsynchronous(true);
+                mHandler.sendMessage(msg);
             }
         }
     }
diff --git a/core/java/android/view/DisplayList.java b/core/java/android/view/DisplayList.java
index fec0d4b..f60c8f0 100644
--- a/core/java/android/view/DisplayList.java
+++ b/core/java/android/view/DisplayList.java
@@ -27,6 +27,15 @@
  */
 public abstract class DisplayList {
     /**
+     * Flag used when calling
+     * {@link HardwareCanvas#drawDisplayList(DisplayList, int, int, android.graphics.Rect, int)}.
+     * When this flag is set, draw operations lying outside of the bounds of the
+     * display list will be culled early. It is recommeneded to always set this
+     * flag.
+     */
+    public static final int FLAG_CLIP_CHILDREN = 0x1;
+
+    /**
      * Starts recording the display list. All operations performed on the
      * returned canvas are recorded and stored in this display list.
      * 
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 1e92b43..f5fc708 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -385,13 +385,14 @@
     private static native void nSetDisplayListName(int displayList, String name);
 
     @Override
-    public boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty) {
-        return nDrawDisplayList(mRenderer,
-                ((GLES20DisplayList) displayList).getNativeDisplayList(), width, height, dirty);
+    public boolean drawDisplayList(DisplayList displayList, int width, int height,
+            Rect dirty, int flags) {
+        return nDrawDisplayList(mRenderer, ((GLES20DisplayList) displayList).getNativeDisplayList(),
+                width, height, dirty, flags);
     }
 
     private static native boolean nDrawDisplayList(int renderer, int displayList,
-            int width, int height, Rect dirty);
+            int width, int height, Rect dirty, int flags);
 
     @Override
     void outputDisplayList(DisplayList displayList) {
@@ -407,9 +408,12 @@
     void drawHardwareLayer(HardwareLayer layer, float x, float y, Paint paint) {
         final GLES20Layer glLayer = (GLES20Layer) layer;
         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
-        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            nDrawLayer(mRenderer, glLayer.getLayer(), x, y, nativePaint);
+        } finally {
+            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        }
     }
 
     private static native void nDrawLayer(int renderer, int layer, float x, float y, int paint);
@@ -607,10 +611,14 @@
             return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint, saveFlags);
         }
 
+        int count;
         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        int count = nSaveLayer(mRenderer, nativePaint, saveFlags);
-        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            count = nSaveLayer(mRenderer, nativePaint, saveFlags);
+        } finally {
+            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        }
         return count;
     }
 
@@ -620,10 +628,14 @@
     public int saveLayer(float left, float top, float right, float bottom, Paint paint,
             int saveFlags) {
         if (left < right && top < bottom) {
+            int count;
             int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-            int count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
-            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+            try {
+                final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+                count = nSaveLayer(mRenderer, left, top, right, bottom, nativePaint, saveFlags);
+            } finally {
+                if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+            }
             return count;
         }
         return save(saveFlags);
@@ -707,9 +719,12 @@
     public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             Paint paint) {
         int modifiers = setupModifiers(paint);
-        nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle,
-                useCenter, paint.mNativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        try {
+            nDrawArc(mRenderer, oval.left, oval.top, oval.right, oval.bottom,
+                    startAngle, sweepAngle, useCenter, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawArc(int renderer, float left, float top,
@@ -726,10 +741,13 @@
         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing patches
         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            nDrawPatch(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, chunks,
+                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+        } finally {
+            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        }
     }
 
     private static native void nDrawPatch(int renderer, int bitmap, byte[] buffer, byte[] chunks,
@@ -740,9 +758,12 @@
         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, nativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawBitmap(
@@ -753,10 +774,13 @@
         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
-                matrix.native_instance, nativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer,
+                    matrix.native_instance, nativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buff,
@@ -767,23 +791,26 @@
         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
 
-        int left, top, right, bottom;
-        if (src == null) {
-            left = top = 0;
-            right = bitmap.getWidth();
-            bottom = bitmap.getHeight();
-        } else {
-            left = src.left;
-            right = src.right;
-            top = src.top;
-            bottom = src.bottom;
+            int left, top, right, bottom;
+            if (src == null) {
+                left = top = 0;
+                right = bitmap.getWidth();
+                bottom = bitmap.getHeight();
+            } else {
+                left = src.left;
+                right = src.right;
+                top = src.top;
+                bottom = src.bottom;
+            }
+
+            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
-
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     @Override
@@ -791,23 +818,26 @@
         if (bitmap.isRecycled()) throw new IllegalArgumentException("Cannot draw recycled bitmaps");
         // Shaders are ignored when drawing bitmaps
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-
-        float left, top, right, bottom;
-        if (src == null) {
-            left = top = 0;
-            right = bitmap.getWidth();
-            bottom = bitmap.getHeight();
-        } else {
-            left = src.left;
-            right = src.right;
-            top = src.top;
-            bottom = src.bottom;
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+    
+            float left, top, right, bottom;
+            if (src == null) {
+                left = top = 0;
+                right = bitmap.getWidth();
+                bottom = bitmap.getHeight();
+            } else {
+                left = src.left;
+                right = src.right;
+                top = src.top;
+                bottom = src.bottom;
+            }
+    
+            nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
+                    dst.left, dst.top, dst.right, dst.bottom, nativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
-
-        nDrawBitmap(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, left, top, right, bottom,
-                dst.left, dst.top, dst.right, dst.bottom, nativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawBitmap(int renderer, int bitmap, byte[] buffer,
@@ -819,12 +849,15 @@
             int width, int height, boolean hasAlpha, Paint paint) {
         // Shaders are ignored when drawing bitmaps
         int modifier = paint != null ? setupColorFilter(paint) : MODIFIER_NONE;
-        final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
-        final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;
-        nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
-        b.recycle();
-        if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        try {
+            final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
+            final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;
+            nDrawBitmap(mRenderer, b.mNativeBitmap, b.mBuffer, x, y, nativePaint);
+            b.recycle();
+        } finally {
+            if (modifier != MODIFIER_NONE) nResetModifiers(mRenderer, modifier);
+        }
     }
 
     @Override
@@ -854,10 +887,13 @@
         colorOffset = 0;
 
         int modifiers = paint != null ? setupModifiers(bitmap, paint) : MODIFIER_NONE;
-        final int nativePaint = paint == null ? 0 : paint.mNativePaint;        
-        nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
-                verts, vertOffset, colors, colorOffset, nativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        try {
+            final int nativePaint = paint == null ? 0 : paint.mNativePaint;        
+            nDrawBitmapMesh(mRenderer, bitmap.mNativeBitmap, bitmap.mBuffer, meshWidth, meshHeight,
+                    verts, vertOffset, colors, colorOffset, nativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawBitmapMesh(int renderer, int bitmap, byte[] buffer,
@@ -867,8 +903,11 @@
     @Override
     public void drawCircle(float cx, float cy, float radius, Paint paint) {
         int modifiers = setupModifiers(paint);
-        nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);        
+        try {
+            nDrawCircle(mRenderer, cx, cy, radius, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawCircle(int renderer, float cx, float cy,
@@ -901,8 +940,11 @@
             throw new IllegalArgumentException("The lines array must contain 4 elements per line.");
         }
         int modifiers = setupModifiers(paint);
-        nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        try {
+            nDrawLines(mRenderer, pts, offset, count, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawLines(int renderer, float[] points,
@@ -916,8 +958,11 @@
     @Override
     public void drawOval(RectF oval, Paint paint) {
         int modifiers = setupModifiers(paint);
-        nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers); 
+        try {
+            nDrawOval(mRenderer, oval.left, oval.top, oval.right, oval.bottom, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawOval(int renderer, float left, float top,
@@ -933,14 +978,17 @@
     @Override
     public void drawPath(Path path, Paint paint) {
         int modifiers = setupModifiers(paint);
-        if (path.isSimplePath) {
-            if (path.rects != null) {
-                nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
+        try {
+            if (path.isSimplePath) {
+                if (path.rects != null) {
+                    nDrawRects(mRenderer, path.rects.mNativeRegion, paint.mNativePaint);
+                }
+            } else {
+                nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
             }
-        } else {
-            nDrawPath(mRenderer, path.mNativePath, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
         }
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
     }
 
     private static native void nDrawPath(int renderer, int path, int paint);
@@ -1001,8 +1049,11 @@
     @Override
     public void drawPoints(float[] pts, int offset, int count, Paint paint) {
         int modifiers = setupModifiers(paint);
-        nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        try {
+            nDrawPoints(mRenderer, pts, offset, count, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawPoints(int renderer, float[] points,
@@ -1047,8 +1098,11 @@
     @Override
     public void drawRect(float left, float top, float right, float bottom, Paint paint) {
         int modifiers = setupModifiers(paint);
-        nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        try {
+            nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawRect(int renderer, float left, float top,
@@ -1072,9 +1126,12 @@
     @Override
     public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
         int modifiers = setupModifiers(paint);
-        nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
-                rx, ry, paint.mNativePaint);
-        if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);        
+        try {
+            nDrawRoundRect(mRenderer, rect.left, rect.top, rect.right, rect.bottom,
+                    rx, ry, paint.mNativePaint);
+        } finally {
+            if (modifiers != MODIFIER_NONE) nResetModifiers(mRenderer, modifiers);
+        }
     }
 
     private static native void nDrawRoundRect(int renderer, float left, float top,
@@ -1223,17 +1280,17 @@
     }
 
     private int setupModifiers(Bitmap b, Paint paint) {
-        if (b.getConfig() == Bitmap.Config.ALPHA_8) {
+        if (b.getConfig() != Bitmap.Config.ALPHA_8) {
+            final ColorFilter filter = paint.getColorFilter();
+            if (filter != null) {
+                nSetupColorFilter(mRenderer, filter.nativeColorFilter);
+                return MODIFIER_COLOR_FILTER;
+            }
+
+            return MODIFIER_NONE;
+        } else {
             return setupModifiers(paint);
         }
-
-        final ColorFilter filter = paint.getColorFilter();
-        if (filter != null) {
-            nSetupColorFilter(mRenderer, filter.nativeColorFilter);
-            return MODIFIER_COLOR_FILTER;
-        }
-
-        return MODIFIER_NONE;
     }
 
     private int setupModifiers(Paint paint) {
diff --git a/core/java/android/view/GLES20RecordingCanvas.java b/core/java/android/view/GLES20RecordingCanvas.java
index c987f48..c9ba65f 100644
--- a/core/java/android/view/GLES20RecordingCanvas.java
+++ b/core/java/android/view/GLES20RecordingCanvas.java
@@ -143,8 +143,8 @@
     @Override
     public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
             int vertOffset, int[] colors, int colorOffset, Paint paint) {
-        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset,
-                paint);
+        super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset,
+                colors, colorOffset, paint);
         mDisplayList.mBitmaps.add(bitmap);
         // Shaders in the Paint are ignored when drawing a Bitmap
     }
diff --git a/core/java/android/view/HardwareCanvas.java b/core/java/android/view/HardwareCanvas.java
index cbdbbde..838c03c 100644
--- a/core/java/android/view/HardwareCanvas.java
+++ b/core/java/android/view/HardwareCanvas.java
@@ -57,11 +57,14 @@
      * @param height The height of the display list.
      * @param dirty The dirty region to redraw in the next pass, matters only
      *        if this method returns true, can be null.
+     * @param flags Optional flags about drawing, see {@link DisplayList} for
+     *              the possible flags.
      * 
      * @return True if the content of the display list requires another
      *         drawing pass (invalidate()), false otherwise
      */
-    public abstract boolean drawDisplayList(DisplayList displayList, int width, int height, Rect dirty);
+    public abstract boolean drawDisplayList(DisplayList displayList, int width, int height,
+            Rect dirty, int flags);
 
     /**
      * Outputs the specified display list to the log. This method exists for use by
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 67466a4..ec95863 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -969,7 +969,8 @@
                             }
 
                             boolean invalidateNeeded = canvas.drawDisplayList(displayList,
-                                    view.getWidth(), view.getHeight(), mRedrawClip);
+                                    view.getWidth(), view.getHeight(), mRedrawClip,
+                                    DisplayList.FLAG_CLIP_CHILDREN);
 
                             if (mProfileEnabled) {
                                 long now = System.nanoTime();
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 6726c56e..c658a80 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -384,7 +384,7 @@
         if (!mHaveFrame) {
             return;
         }
-        ViewRootImpl viewRoot = (ViewRootImpl) getRootView().getParent();
+        ViewRootImpl viewRoot = getViewRootImpl();
         if (viewRoot != null) {
             mTranslator = viewRoot.mTranslator;
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 363c30d..81151b0 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -601,6 +601,8 @@
  * @attr ref android.R.styleable#View_paddingLeft
  * @attr ref android.R.styleable#View_paddingRight
  * @attr ref android.R.styleable#View_paddingTop
+ * @attr ref android.R.styleable#View_paddingStart
+ * @attr ref android.R.styleable#View_paddingEnd
  * @attr ref android.R.styleable#View_saveEnabled
  * @attr ref android.R.styleable#View_rotation
  * @attr ref android.R.styleable#View_rotationX
@@ -1757,6 +1759,16 @@
     static final int LAYOUT_DIRECTION_RESOLVED = 0x00000008;
 
 
+    /**
+     * Indicates that the view is tracking some sort of transient state
+     * that the app should not need to be aware of, but that the framework
+     * should take special care to preserve.
+     *
+     * @hide
+     */
+    static final int HAS_TRANSIENT_STATE = 0x00000010;
+
+
     /* End of masks for mPrivateFlags2 */
 
     static final int DRAG_MASK = DRAG_CAN_ACCEPT | DRAG_HOVERED;
@@ -4887,6 +4899,43 @@
     }
 
     /**
+     * Indicates whether the view is currently tracking transient state that the
+     * app should not need to concern itself with saving and restoring, but that
+     * the framework should take special note to preserve when possible.
+     *
+     * @return true if the view has transient state
+     *
+     * @hide
+     */
+    @ViewDebug.ExportedProperty(category = "layout")
+    public boolean hasTransientState() {
+        return (mPrivateFlags2 & HAS_TRANSIENT_STATE) == HAS_TRANSIENT_STATE;
+    }
+
+    /**
+     * Set whether this view is currently tracking transient state that the
+     * framework should attempt to preserve when possible.
+     *
+     * @param hasTransientState true if this view has transient state
+     *
+     * @hide
+     */
+    public void setHasTransientState(boolean hasTransientState) {
+        if (hasTransientState() == hasTransientState) return;
+
+        mPrivateFlags2 = (mPrivateFlags2 & ~HAS_TRANSIENT_STATE) |
+                (hasTransientState ? HAS_TRANSIENT_STATE : 0);
+        if (mParent != null) {
+            try {
+                mParent.childHasTransientStateChanged(this, hasTransientState);
+            } catch (AbstractMethodError e) {
+                Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName() +
+                        " does not fully implement ViewParent", e);
+            }
+        }
+    }
+
+    /**
      * If this view doesn't do any drawing on its own, set this flag to
      * allow further optimizations. By default, this flag is not set on
      * View, but could be set on some View subclasses such as ViewGroup.
@@ -4997,6 +5046,10 @@
      *        the View's internal state from a previously set "pressed" state.
      */
     public void setPressed(boolean pressed) {
+        if (pressed == ((mPrivateFlags & PRESSED) == PRESSED)) {
+            return;
+        }
+
         if (pressed) {
             mPrivateFlags |= PRESSED;
         } else {
@@ -5440,12 +5493,6 @@
         return true;
     }
 
-    /** Gets the ViewAncestor, or null if not attached. */
-    /*package*/ ViewRootImpl getViewRootImpl() {
-        View root = getRootView();
-        return root != null ? (ViewRootImpl)root.getParent() : null;
-    }
-
     /**
      * Call this to try to give focus to a specific view or to one of its descendants. This is a
      * special variant of {@link #requestFocus() } that will allow views that are not focuable in
@@ -6505,8 +6552,7 @@
 
         if ((viewFlags & ENABLED_MASK) == DISABLED) {
             if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PRESSED) != 0) {
-                mPrivateFlags &= ~PRESSED;
-                refreshDrawableState();
+                setPressed(false);
             }
             // A disabled view that is clickable still consumes the touch
             // events, it just doesn't respond to them.
@@ -6538,8 +6584,7 @@
                             // showed it as pressed.  Make it show the pressed
                             // state now (before scheduling the click) to ensure
                             // the user sees it.
-                            mPrivateFlags |= PRESSED;
-                            refreshDrawableState();
+                            setPressed(true);
                        }
 
                         if (!mHasPerformedLongPress) {
@@ -6595,15 +6640,13 @@
                         postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                     } else {
                         // Not inside a scrolling container, so show the feedback right away
-                        mPrivateFlags |= PRESSED;
-                        refreshDrawableState();
+                        setPressed(true);
                         checkForLongClick(0);
                     }
                     break;
 
                 case MotionEvent.ACTION_CANCEL:
-                    mPrivateFlags &= ~PRESSED;
-                    refreshDrawableState();
+                    setPressed(false);
                     removeTapCallback();
                     break;
 
@@ -6619,9 +6662,7 @@
                             // Remove any future long press/tap checks
                             removeLongPressCallback();
 
-                            // Need to switch from pressed to not pressed
-                            mPrivateFlags &= ~PRESSED;
-                            refreshDrawableState();
+                            setPressed(false);
                         }
                     }
                     break;
@@ -8683,6 +8724,18 @@
     }
 
     /**
+     * Gets the view root associated with the View.
+     * @return The view root, or null if none.
+     * @hide
+     */
+    public ViewRootImpl getViewRootImpl() {
+        if (mAttachInfo != null) {
+            return mAttachInfo.mViewRootImpl;
+        }
+        return null;
+    }
+
+    /**
      * <p>Causes the Runnable to be added to the message queue.
      * The runnable will be run on the user interface thread.</p>
      * 
@@ -8696,17 +8749,13 @@
      *         looper processing the message queue is exiting.
      */
     public boolean post(Runnable action) {
-        Handler handler;
-        AttachInfo attachInfo = mAttachInfo;
+        final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
-            handler = attachInfo.mHandler;
-        } else {
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().post(action);
-            return true;
+            return attachInfo.mHandler.post(action);
         }
-
-        return handler.post(action);
+        // Assume that post will succeed later
+        ViewRootImpl.getRunQueue().post(action);
+        return true;
     }
 
     /**
@@ -8729,17 +8778,13 @@
      *         occurs then the message will be dropped.
      */
     public boolean postDelayed(Runnable action, long delayMillis) {
-        Handler handler;
-        AttachInfo attachInfo = mAttachInfo;
+        final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
-            handler = attachInfo.mHandler;
-        } else {
-            // Assume that post will succeed later
-            ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
-            return true;
+            return attachInfo.mHandler.postDelayed(action, delayMillis);
         }
-
-        return handler.postDelayed(action, delayMillis);
+        // Assume that post will succeed later
+        ViewRootImpl.getRunQueue().postDelayed(action, delayMillis);
+        return true;
     }
 
     /**
@@ -8756,17 +8801,13 @@
      *         (for instance, if the Runnable was not in the queue already.)
      */
     public boolean removeCallbacks(Runnable action) {
-        Handler handler;
-        AttachInfo attachInfo = mAttachInfo;
+        final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
-            handler = attachInfo.mHandler;
+            attachInfo.mHandler.removeCallbacks(action);
         } else {
             // Assume that post will succeed later
             ViewRootImpl.getRunQueue().removeCallbacks(action);
-            return true;
         }
-
-        handler.removeCallbacks(action);
         return true;
     }
 
@@ -8815,12 +8856,9 @@
     public void postInvalidateDelayed(long delayMilliseconds) {
         // We try only with the AttachInfo because there's no point in invalidating
         // if we are not attached to our window
-        AttachInfo attachInfo = mAttachInfo;
+        final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
-            Message msg = Message.obtain();
-            msg.what = AttachInfo.INVALIDATE_MSG;
-            msg.obj = this;
-            attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+            attachInfo.mViewRootImpl.dispatchInvalidateDelayed(this, delayMilliseconds);
         }
     }
 
@@ -8843,7 +8881,7 @@
 
         // We try only with the AttachInfo because there's no point in invalidating
         // if we are not attached to our window
-        AttachInfo attachInfo = mAttachInfo;
+        final AttachInfo attachInfo = mAttachInfo;
         if (attachInfo != null) {
             final AttachInfo.InvalidateInfo info = AttachInfo.InvalidateInfo.acquire();
             info.target = this;
@@ -8852,10 +8890,7 @@
             info.right = right;
             info.bottom = bottom;
 
-            final Message msg = Message.obtain();
-            msg.what = AttachInfo.INVALIDATE_RECT_MSG;
-            msg.obj = info;
-            attachInfo.mHandler.sendMessageDelayed(msg, delayMilliseconds);
+            attachInfo.mViewRootImpl.dispatchInvalidateRectDelayed(info, delayMilliseconds);
         }
     }
 
@@ -9540,10 +9575,6 @@
         // Clear any previous layout direction resolution
         mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED_RTL;
 
-        // Reset also TextDirection as a change into LayoutDirection may impact the selected
-        // TextDirectionHeuristic
-        resetResolvedTextDirection();
-
         // Set resolved depending on layout direction
         switch (getLayoutDirection()) {
             case LAYOUT_DIRECTION_INHERIT:
@@ -9580,14 +9611,15 @@
     }
 
     /**
-     * @hide
+     * Force padding depending on layout direction.
      */
-    protected void resolvePadding() {
+    public void resolvePadding() {
         // If the user specified the absolute padding (either with android:padding or
         // android:paddingLeft/Top/Right/Bottom), use this padding, otherwise
         // use the default padding or the padding from the background drawable
         // (stored at this point in mPadding*)
-        switch (getResolvedLayoutDirection()) {
+        int resolvedLayoutDirection = getResolvedLayoutDirection();
+        switch (resolvedLayoutDirection) {
             case LAYOUT_DIRECTION_RTL:
                 // Start user padding override Right user padding. Otherwise, if Right user
                 // padding is not defined, use the default Right padding. If Right user padding
@@ -9623,6 +9655,18 @@
         mUserPaddingBottom = (mUserPaddingBottom >= 0) ? mUserPaddingBottom : mPaddingBottom;
 
         recomputePadding();
+        onResolvePadding(resolvedLayoutDirection);
+    }
+
+    /**
+     * Resolve padding depending on the layout direction. Subclasses that care about
+     * padding resolution should override this method. The default implementation does
+     * nothing.
+     *
+     * @param layoutDirection the direction of the layout
+     *
+     */
+    public void onResolvePadding(int layoutDirection) {
     }
 
     /**
@@ -9649,8 +9693,10 @@
      * @hide
      */
     protected void resetResolvedLayoutDirection() {
-        // Reset the current View resolution
+        // Reset the layout direction resolution
         mPrivateFlags2 &= ~LAYOUT_DIRECTION_RESOLVED;
+        // Reset also the text direction
+        resetResolvedTextDirection();
     }
 
     /**
@@ -9689,13 +9735,12 @@
         }
 
         if (mAttachInfo != null) {
-            mAttachInfo.mHandler.removeMessages(AttachInfo.INVALIDATE_MSG, this);
+            mAttachInfo.mViewRootImpl.cancelInvalidate(this);
         }
 
         mCurrentAnimation = null;
 
         resetResolvedLayoutDirection();
-        resetResolvedTextDirection();
     }
 
     /**
@@ -11209,7 +11254,7 @@
                 } else {
                     mPrivateFlags &= ~DIRTY_MASK;
                     ((HardwareCanvas) canvas).drawDisplayList(displayList,
-                            mRight - mLeft, mBottom - mTop, null);
+                            mRight - mLeft, mBottom - mTop, null, flags);
                 }
             }
         } else if (cache != null) {
@@ -14070,7 +14115,6 @@
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE},
-     *
      */
     public int getTextDirection() {
         return mTextDirection;
@@ -14087,7 +14131,6 @@
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE},
-     *
      */
     public void setTextDirection(int textDirection) {
         if (textDirection != mTextDirection) {
@@ -14107,7 +14150,6 @@
      * {@link #TEXT_DIRECTION_LTR},
      * {@link #TEXT_DIRECTION_RTL},
      * {@link #TEXT_DIRECTION_LOCALE},
-     *
      */
     public int getResolvedTextDirection() {
         if (mResolvedTextDirection == TEXT_DIRECTION_INHERIT) {
@@ -14117,27 +14159,47 @@
     }
 
     /**
-     * Resolve the text direction.
-     *
+     * Resolve the text direction. Will call {@link View#onResolveTextDirection()} when resolution
+     * is done.
      */
-    protected void resolveTextDirection() {
+    public void resolveTextDirection() {
+        if (mResolvedTextDirection != TEXT_DIRECTION_INHERIT) {
+            // Resolution has already been done.
+            return;
+        }
         if (mTextDirection != TEXT_DIRECTION_INHERIT) {
             mResolvedTextDirection = mTextDirection;
-            return;
-        }
-        if (mParent != null && mParent instanceof ViewGroup) {
+        } else if (mParent != null && mParent instanceof ViewGroup) {
             mResolvedTextDirection = ((ViewGroup) mParent).getResolvedTextDirection();
-            return;
+        } else {
+            mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
         }
-        mResolvedTextDirection = TEXT_DIRECTION_FIRST_STRONG;
+        onResolveTextDirection();
     }
 
     /**
-     * Reset resolved text direction. Will be resolved during a call to getResolvedTextDirection().
-     *
+     * Called when text direction has been resolved. Subclasses that care about text direction
+     * resolution should override this method. The default implementation does nothing.
      */
-    protected void resetResolvedTextDirection() {
+    public void onResolveTextDirection() {
+    }
+
+    /**
+     * Reset resolved text direction. Text direction can be resolved with a call to
+     * getResolvedTextDirection(). Will call {@link View#onResetResolvedTextDirection()} when
+     * reset is done.
+     */
+    public void resetResolvedTextDirection() {
         mResolvedTextDirection = TEXT_DIRECTION_INHERIT;
+        onResetResolvedTextDirection();
+    }
+
+    /**
+     * Called when text direction is reset. Subclasses that care about text direction reset should
+     * override this method and do a reset of the text direction of their children. The default
+     * implementation does nothing.
+     */
+    public void onResetResolvedTextDirection() {
     }
 
     //
@@ -14441,8 +14503,7 @@
     private final class CheckForTap implements Runnable {
         public void run() {
             mPrivateFlags &= ~PREPRESSED;
-            mPrivateFlags |= PRESSED;
-            refreshDrawableState();
+            setPressed(true);
             checkForLongClick(ViewConfiguration.getTapTimeout());
         }
     }
@@ -14962,24 +15023,17 @@
         Canvas mCanvas;
 
         /**
+         * The view root impl.
+         */
+        final ViewRootImpl mViewRootImpl;
+
+        /**
          * A Handler supplied by a view's {@link android.view.ViewRootImpl}. This
          * handler can be used to pump events in the UI events queue.
          */
         final Handler mHandler;
 
         /**
-         * Identifier for messages requesting the view to be invalidated.
-         * Such messages should be sent to {@link #mHandler}.
-         */
-        static final int INVALIDATE_MSG = 0x1;
-
-        /**
-         * Identifier for messages requesting the view to invalidate a region.
-         * Such messages should be sent to {@link #mHandler}.
-         */
-        static final int INVALIDATE_RECT_MSG = 0x2;
-
-        /**
          * Temporary for use in computing invalidate rectangles while
          * calling up the hierarchy.
          */
@@ -15007,10 +15061,11 @@
          * @param handler the events handler the view must use
          */
         AttachInfo(IWindowSession session, IWindow window,
-                Handler handler, Callbacks effectPlayer) {
+                ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
             mSession = session;
             mWindow = window;
             mWindowToken = window.asBinder();
+            mViewRootImpl = viewRootImpl;
             mHandler = handler;
             mRootCallbacks = effectPlayer;
         }
diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java
index c1db572..2a17845 100644
--- a/core/java/android/view/ViewDebug.java
+++ b/core/java/android/view/ViewDebug.java
@@ -375,7 +375,7 @@
     }
 
     private static BufferedWriter sHierarchyTraces;
-    private static ViewRootImpl sHierarhcyRoot;
+    private static ViewRootImpl sHierarchyRoot;
     private static String sHierarchyTracePrefix;
 
     /**
@@ -855,7 +855,7 @@
             return;
         }
 
-        if (sHierarhcyRoot != null) {
+        if (sHierarchyRoot != null) {
             throw new IllegalStateException("You must call stopHierarchyTracing() before running" +
                 " a new trace!");
         }
@@ -874,7 +874,7 @@
             return;
         }
 
-        sHierarhcyRoot = (ViewRootImpl) view.getRootView().getParent();
+        sHierarchyRoot = view.getViewRootImpl();
     }
 
     /**
@@ -896,7 +896,7 @@
             return;
         }
 
-        if (sHierarhcyRoot == null || sHierarchyTraces == null) {
+        if (sHierarchyRoot == null || sHierarchyTraces == null) {
             throw new IllegalStateException("You must call startHierarchyTracing() before" +
                 " stopHierarchyTracing()!");
         }
@@ -921,7 +921,7 @@
             return;
         }
 
-        View view = sHierarhcyRoot.getView();
+        View view = sHierarchyRoot.getView();
         if (view instanceof ViewGroup) {
             ViewGroup group = (ViewGroup) view;
             dumpViewHierarchy(group, out, 0);
@@ -932,7 +932,7 @@
             }
         }
 
-        sHierarhcyRoot = null;
+        sHierarchyRoot = null;
     }
 
     static void dispatchCommand(View view, String command, String parameters,
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index e6a8334..c68d77d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -77,6 +77,7 @@
  * @attr ref android.R.styleable#ViewGroup_animateLayoutChanges
  */
 public abstract class ViewGroup extends View implements ViewParent, ViewManager {
+    private static final String TAG = "ViewGroup";
 
     private static final boolean DBG = false;
 
@@ -168,6 +169,11 @@
      */
     protected int mGroupFlags;
 
+    /**
+     * NOTE: If you change the flags below make sure to reflect the changes
+     *       the DisplayList class
+     */
+    
     // When set, ViewGroup invalidates only the child's rectangle
     // Set by default
     static final int FLAG_CLIP_CHILDREN = 0x1;
@@ -370,6 +376,10 @@
     @ViewDebug.ExportedProperty(category = "drawing")
     boolean mDrawLayers = true;
 
+    // Indicates how many of this container's child subtrees contain transient state
+    @ViewDebug.ExportedProperty(category = "layout")
+    private int mChildCountWithTransientState = 0;
+
     public ViewGroup(Context context) {
         super(context);
         initViewGroup();
@@ -648,6 +658,38 @@
     }
 
     /**
+     * Called when a child view has changed whether or not it is tracking transient state.
+     *
+     * @hide
+     */
+    public void childHasTransientStateChanged(View child, boolean childHasTransientState) {
+        final boolean oldHasTransientState = hasTransientState();
+        if (childHasTransientState) {
+            mChildCountWithTransientState++;
+        } else {
+            mChildCountWithTransientState--;
+        }
+
+        final boolean newHasTransientState = hasTransientState();
+        if (mParent != null && oldHasTransientState != newHasTransientState) {
+            try {
+                mParent.childHasTransientStateChanged(this, newHasTransientState);
+            } catch (AbstractMethodError e) {
+                Log.e(TAG, mParent.getClass().getSimpleName() +
+                        " does not fully implement ViewParent", e);
+            }
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean hasTransientState() {
+        return mChildCountWithTransientState > 0 || super.hasTransientState();
+    }
+
+    /**
      * {@inheritDoc}
      */
     @Override
@@ -3094,6 +3136,10 @@
         if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) {
             mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE;
         }
+
+        if (child.hasTransientState()) {
+            childHasTransientStateChanged(child, true);
+        }
     }
 
     private void addInArray(View child, int index) {
@@ -3290,6 +3336,10 @@
            view.dispatchDetachedFromWindow();
         }
 
+        if (view.hasTransientState()) {
+            childHasTransientStateChanged(view, false);
+        }
+
         onViewRemoved(view);
 
         needGlobalAttributesUpdate(false);
@@ -3361,6 +3411,10 @@
                view.dispatchDetachedFromWindow();
             }
 
+            if (view.hasTransientState()) {
+                childHasTransientStateChanged(view, false);
+            }
+
             needGlobalAttributesUpdate(false);
 
             onViewRemoved(view);
@@ -3426,6 +3480,10 @@
                view.dispatchDetachedFromWindow();
             }
 
+            if (view.hasTransientState()) {
+                childHasTransientStateChanged(view, false);
+            }
+
             onViewRemoved(view);
 
             view.mParent = null;
@@ -3466,6 +3524,10 @@
             child.dispatchDetachedFromWindow();
         }
 
+        if (child.hasTransientState()) {
+            childHasTransientStateChanged(child, false);
+        }
+
         onViewRemoved(child);
     }
 
@@ -3727,7 +3789,8 @@
                         RectF boundingRect = attachInfo.mTmpTransformRect;
                         boundingRect.set(dirty);
                         m.mapRect(boundingRect);
-                        dirty.set((int) boundingRect.left, (int) boundingRect.top,
+                        dirty.set((int) (boundingRect.left - 0.5f),
+                                (int) (boundingRect.top - 0.5f),
                                 (int) (boundingRect.right + 0.5f),
                                 (int) (boundingRect.bottom + 0.5f));
                     }
@@ -4857,9 +4920,7 @@
     }
 
     @Override
-    protected void resetResolvedTextDirection() {
-        super.resetResolvedTextDirection();
-
+    public void onResetResolvedTextDirection() {
         // Take care of resetting the children resolution too
         final int count = getChildCount();
         for (int i = 0; i < count; i++) {
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 873d4bb..8395f1b 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -261,4 +261,14 @@
      * @return True if the event was sent.
      */
     public boolean requestSendAccessibilityEvent(View child, AccessibilityEvent event);
+
+    /**
+     * Called when a child view now has or no longer is tracking transient state.
+     *
+     * @param child Child view whose state has changed
+     * @param hasTransientState true if this child has transient state
+     *
+     * @hide
+     */
+    public void childHasTransientStateChanged(View child, boolean hasTransientState);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fbcb423..28737fc 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -61,6 +61,7 @@
 import android.util.Pools;
 import android.util.Slog;
 import android.util.TypedValue;
+import android.view.View.AttachInfo;
 import android.view.View.MeasureSpec;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
@@ -96,7 +97,7 @@
  * {@hide}
  */
 @SuppressWarnings({"EmptyCatchBlock", "PointlessBooleanExpression"})
-public final class ViewRootImpl extends Handler implements ViewParent,
+public final class ViewRootImpl implements ViewParent,
         View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks {
     private static final String TAG = "ViewRootImpl";
     private static final boolean DBG = false;
@@ -212,6 +213,7 @@
     final Rect mVisRect; // used to retrieve visible rect of focused view.
 
     boolean mTraversalScheduled;
+    int mTraversalBarrier;
     long mLastTraversalFinishedTimeNanos;
     long mLastDrawFinishedTimeNanos;
     boolean mWillDrawSoon;
@@ -379,7 +381,7 @@
             new AccessibilityInteractionConnectionManager();
         mAccessibilityManager.addAccessibilityStateChangeListener(
                 mAccessibilityInteractionConnectionManager);
-        mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, this);
+        mAttachInfo = new View.AttachInfo(sWindowSession, mWindow, this, mHandler, this);
         mViewConfiguration = ViewConfiguration.get(context);
         mDensity = context.getResources().getDisplayMetrics().densityDpi;
         mFallbackEventHandler = PolicyManager.makeNewFallbackEventHandler(context);
@@ -838,22 +840,28 @@
     public void scheduleTraversals() {
         if (!mTraversalScheduled) {
             mTraversalScheduled = true;
+            mTraversalBarrier = mHandler.getLooper().postSyncBarrier();
             scheduleFrame();
         }
     }
 
     public void unscheduleTraversals() {
-        mTraversalScheduled = false;
+        if (mTraversalScheduled) {
+            mTraversalScheduled = false;
+            mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
+        }
     }
 
     void scheduleFrame() {
         if (!mFrameScheduled) {
-            mChoreographer.postDrawCallback(mFrameRunnable);
             mFrameScheduled = true;
+            mChoreographer.postDrawCallback(mFrameRunnable);
         }
     }
 
     void unscheduleFrame() {
+        unscheduleTraversals();
+
         if (mFrameScheduled) {
             mFrameScheduled = false;
             mChoreographer.removeDrawCallback(mFrameRunnable);
@@ -868,6 +876,7 @@
 
         if (mTraversalScheduled) {
             mTraversalScheduled = false;
+            mHandler.getLooper().removeSyncBarrier(mTraversalBarrier);
             doTraversal();
         }
     }
@@ -1929,7 +1938,7 @@
                 sFirstDrawComplete = true;
                 final int count = sFirstDrawHandlers.size();
                 for (int i = 0; i< count; i++) {
-                    post(sFirstDrawHandlers.get(i));
+                    mHandler.post(sFirstDrawHandlers.get(i));
                 }
             }
         }
@@ -2441,283 +2450,289 @@
         }
     }
 
-    public final static int DIE = 1001;
-    public final static int RESIZED = 1002;
-    public final static int RESIZED_REPORT = 1003;
-    public final static int WINDOW_FOCUS_CHANGED = 1004;
-    public final static int DISPATCH_KEY = 1005;
-    public final static int DISPATCH_APP_VISIBILITY = 1008;
-    public final static int DISPATCH_GET_NEW_SURFACE = 1009;
-    public final static int IME_FINISHED_EVENT = 1010;
-    public final static int DISPATCH_KEY_FROM_IME = 1011;
-    public final static int FINISH_INPUT_CONNECTION = 1012;
-    public final static int CHECK_FOCUS = 1013;
-    public final static int CLOSE_SYSTEM_DIALOGS = 1014;
-    public final static int DISPATCH_DRAG_EVENT = 1015;
-    public final static int DISPATCH_DRAG_LOCATION_EVENT = 1016;
-    public final static int DISPATCH_SYSTEM_UI_VISIBILITY = 1017;
-    public final static int DISPATCH_GENERIC_MOTION = 1018;
-    public final static int UPDATE_CONFIGURATION = 1019;
-    public final static int DO_PERFORM_ACCESSIBILITY_ACTION = 1020;
-    public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 1021;
-    public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 1022;
-    public final static int DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 1023;
-    public final static int DO_PROCESS_INPUT_EVENTS = 1024;
+    private final static int MSG_INVALIDATE = 1;
+    private final static int MSG_INVALIDATE_RECT = 2;
+    private final static int MSG_DIE = 3;
+    private final static int MSG_RESIZED = 4;
+    private final static int MSG_RESIZED_REPORT = 5;
+    private final static int MSG_WINDOW_FOCUS_CHANGED = 6;
+    private final static int MSG_DISPATCH_KEY = 7;
+    private final static int MSG_DISPATCH_APP_VISIBILITY = 8;
+    private final static int MSG_DISPATCH_GET_NEW_SURFACE = 9;
+    private final static int MSG_IME_FINISHED_EVENT = 10;
+    private final static int MSG_DISPATCH_KEY_FROM_IME = 11;
+    private final static int MSG_FINISH_INPUT_CONNECTION = 12;
+    private final static int MSG_CHECK_FOCUS = 13;
+    private final static int MSG_CLOSE_SYSTEM_DIALOGS = 14;
+    private final static int MSG_DISPATCH_DRAG_EVENT = 15;
+    private final static int MSG_DISPATCH_DRAG_LOCATION_EVENT = 16;
+    private final static int MSG_DISPATCH_SYSTEM_UI_VISIBILITY = 17;
+    private final static int MSG_UPDATE_CONFIGURATION = 18;
+    private final static int MSG_PERFORM_ACCESSIBILITY_ACTION = 19;
+    private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID = 20;
+    private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID = 21;
+    private final static int MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT = 22;
+    private final static int MSG_PROCESS_INPUT_EVENTS = 23;
 
-    @Override
-    public String getMessageName(Message message) {
-        switch (message.what) {
-            case DIE:
-                return "DIE";
-            case RESIZED:
-                return "RESIZED";
-            case RESIZED_REPORT:
-                return "RESIZED_REPORT";
-            case WINDOW_FOCUS_CHANGED:
-                return "WINDOW_FOCUS_CHANGED";
-            case DISPATCH_KEY:
-                return "DISPATCH_KEY";
-            case DISPATCH_APP_VISIBILITY:
-                return "DISPATCH_APP_VISIBILITY";
-            case DISPATCH_GET_NEW_SURFACE:
-                return "DISPATCH_GET_NEW_SURFACE";
-            case IME_FINISHED_EVENT:
-                return "IME_FINISHED_EVENT";
-            case DISPATCH_KEY_FROM_IME:
-                return "DISPATCH_KEY_FROM_IME";
-            case FINISH_INPUT_CONNECTION:
-                return "FINISH_INPUT_CONNECTION";
-            case CHECK_FOCUS:
-                return "CHECK_FOCUS";
-            case CLOSE_SYSTEM_DIALOGS:
-                return "CLOSE_SYSTEM_DIALOGS";
-            case DISPATCH_DRAG_EVENT:
-                return "DISPATCH_DRAG_EVENT";
-            case DISPATCH_DRAG_LOCATION_EVENT:
-                return "DISPATCH_DRAG_LOCATION_EVENT";
-            case DISPATCH_SYSTEM_UI_VISIBILITY:
-                return "DISPATCH_SYSTEM_UI_VISIBILITY";
-            case DISPATCH_GENERIC_MOTION:
-                return "DISPATCH_GENERIC_MOTION";
-            case UPDATE_CONFIGURATION:
-                return "UPDATE_CONFIGURATION";
-            case DO_PERFORM_ACCESSIBILITY_ACTION:
-                return "DO_PERFORM_ACCESSIBILITY_ACTION";
-            case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
-                return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
-            case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
-                return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
-            case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
-                return "DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
-            case DO_PROCESS_INPUT_EVENTS:
-                return "DO_PROCESS_INPUT_EVENTS";
+    final class ViewRootHandler extends Handler {
+        @Override
+        public String getMessageName(Message message) {
+            switch (message.what) {
+                case MSG_INVALIDATE:
+                    return "MSG_INVALIDATE";
+                case MSG_INVALIDATE_RECT:
+                    return "MSG_INVALIDATE_RECT";
+                case MSG_DIE:
+                    return "MSG_DIE";
+                case MSG_RESIZED:
+                    return "MSG_RESIZED";
+                case MSG_RESIZED_REPORT:
+                    return "MSG_RESIZED_REPORT";
+                case MSG_WINDOW_FOCUS_CHANGED:
+                    return "MSG_WINDOW_FOCUS_CHANGED";
+                case MSG_DISPATCH_KEY:
+                    return "MSG_DISPATCH_KEY";
+                case MSG_DISPATCH_APP_VISIBILITY:
+                    return "MSG_DISPATCH_APP_VISIBILITY";
+                case MSG_DISPATCH_GET_NEW_SURFACE:
+                    return "MSG_DISPATCH_GET_NEW_SURFACE";
+                case MSG_IME_FINISHED_EVENT:
+                    return "MSG_IME_FINISHED_EVENT";
+                case MSG_DISPATCH_KEY_FROM_IME:
+                    return "MSG_DISPATCH_KEY_FROM_IME";
+                case MSG_FINISH_INPUT_CONNECTION:
+                    return "MSG_FINISH_INPUT_CONNECTION";
+                case MSG_CHECK_FOCUS:
+                    return "MSG_CHECK_FOCUS";
+                case MSG_CLOSE_SYSTEM_DIALOGS:
+                    return "MSG_CLOSE_SYSTEM_DIALOGS";
+                case MSG_DISPATCH_DRAG_EVENT:
+                    return "MSG_DISPATCH_DRAG_EVENT";
+                case MSG_DISPATCH_DRAG_LOCATION_EVENT:
+                    return "MSG_DISPATCH_DRAG_LOCATION_EVENT";
+                case MSG_DISPATCH_SYSTEM_UI_VISIBILITY:
+                    return "MSG_DISPATCH_SYSTEM_UI_VISIBILITY";
+                case MSG_UPDATE_CONFIGURATION:
+                    return "MSG_UPDATE_CONFIGURATION";
+                case MSG_PERFORM_ACCESSIBILITY_ACTION:
+                    return "MSG_PERFORM_ACCESSIBILITY_ACTION";
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID:
+                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID";
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID:
+                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID";
+                case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT:
+                    return "MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT";
+                case MSG_PROCESS_INPUT_EVENTS:
+                    return "MSG_PROCESS_INPUT_EVENTS";
+            }
+            return super.getMessageName(message);
         }
-        return super.getMessageName(message);
-    }
 
-    @Override
-    public void handleMessage(Message msg) {
-        switch (msg.what) {
-        case View.AttachInfo.INVALIDATE_MSG:
-            ((View) msg.obj).invalidate();
-            break;
-        case View.AttachInfo.INVALIDATE_RECT_MSG:
-            final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
-            info.target.invalidate(info.left, info.top, info.right, info.bottom);
-            info.release();
-            break;
-        case IME_FINISHED_EVENT:
-            handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
-            break;
-        case DO_PROCESS_INPUT_EVENTS:
-            mProcessInputEventsScheduled = false;
-            doProcessInputEvents();
-            break;
-        case DISPATCH_APP_VISIBILITY:
-            handleAppVisibility(msg.arg1 != 0);
-            break;
-        case DISPATCH_GET_NEW_SURFACE:
-            handleGetNewSurface();
-            break;
-        case RESIZED:
-            ResizedInfo ri = (ResizedInfo)msg.obj;
-
-            if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
-                    && mPendingContentInsets.equals(ri.coveredInsets)
-                    && mPendingVisibleInsets.equals(ri.visibleInsets)
-                    && ((ResizedInfo)msg.obj).newConfig == null) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+            case MSG_INVALIDATE:
+                ((View) msg.obj).invalidate();
                 break;
-            }
-            // fall through...
-        case RESIZED_REPORT:
-            if (mAdded) {
-                Configuration config = ((ResizedInfo)msg.obj).newConfig;
-                if (config != null) {
-                    updateConfiguration(config, false);
-                }
-                mWinFrame.left = 0;
-                mWinFrame.right = msg.arg1;
-                mWinFrame.top = 0;
-                mWinFrame.bottom = msg.arg2;
-                mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
-                mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
-                if (msg.what == RESIZED_REPORT) {
-                    mReportNextDraw = true;
-                }
+            case MSG_INVALIDATE_RECT:
+                final View.AttachInfo.InvalidateInfo info = (View.AttachInfo.InvalidateInfo) msg.obj;
+                info.target.invalidate(info.left, info.top, info.right, info.bottom);
+                info.release();
+                break;
+            case MSG_IME_FINISHED_EVENT:
+                handleImeFinishedEvent(msg.arg1, msg.arg2 != 0);
+                break;
+            case MSG_PROCESS_INPUT_EVENTS:
+                mProcessInputEventsScheduled = false;
+                doProcessInputEvents();
+                break;
+            case MSG_DISPATCH_APP_VISIBILITY:
+                handleAppVisibility(msg.arg1 != 0);
+                break;
+            case MSG_DISPATCH_GET_NEW_SURFACE:
+                handleGetNewSurface();
+                break;
+            case MSG_RESIZED:
+                ResizedInfo ri = (ResizedInfo)msg.obj;
 
-                if (mView != null) {
-                    forceLayout(mView);
+                if (mWinFrame.width() == msg.arg1 && mWinFrame.height() == msg.arg2
+                        && mPendingContentInsets.equals(ri.coveredInsets)
+                        && mPendingVisibleInsets.equals(ri.visibleInsets)
+                        && ((ResizedInfo)msg.obj).newConfig == null) {
+                    break;
                 }
-                requestLayout();
-            }
-            break;
-        case WINDOW_FOCUS_CHANGED: {
-            if (mAdded) {
-                boolean hasWindowFocus = msg.arg1 != 0;
-                mAttachInfo.mHasWindowFocus = hasWindowFocus;
-                
-                profileRendering(hasWindowFocus);
+                // fall through...
+            case MSG_RESIZED_REPORT:
+                if (mAdded) {
+                    Configuration config = ((ResizedInfo)msg.obj).newConfig;
+                    if (config != null) {
+                        updateConfiguration(config, false);
+                    }
+                    mWinFrame.left = 0;
+                    mWinFrame.right = msg.arg1;
+                    mWinFrame.top = 0;
+                    mWinFrame.bottom = msg.arg2;
+                    mPendingContentInsets.set(((ResizedInfo)msg.obj).coveredInsets);
+                    mPendingVisibleInsets.set(((ResizedInfo)msg.obj).visibleInsets);
+                    if (msg.what == MSG_RESIZED_REPORT) {
+                        mReportNextDraw = true;
+                    }
 
-                if (hasWindowFocus) {
-                    boolean inTouchMode = msg.arg2 != 0;
-                    ensureTouchModeLocally(inTouchMode);
+                    if (mView != null) {
+                        forceLayout(mView);
+                    }
+                    requestLayout();
+                }
+                break;
+            case MSG_WINDOW_FOCUS_CHANGED: {
+                if (mAdded) {
+                    boolean hasWindowFocus = msg.arg1 != 0;
+                    mAttachInfo.mHasWindowFocus = hasWindowFocus;
 
-                    if (mAttachInfo.mHardwareRenderer != null &&
-                            mSurface != null && mSurface.isValid()) {
-                        mFullRedrawNeeded = true;
-                        try {
-                            mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
-                                    mHolder);
-                        } catch (Surface.OutOfResourcesException e) {
-                            Log.e(TAG, "OutOfResourcesException locking surface", e);
+                    profileRendering(hasWindowFocus);
+
+                    if (hasWindowFocus) {
+                        boolean inTouchMode = msg.arg2 != 0;
+                        ensureTouchModeLocally(inTouchMode);
+
+                        if (mAttachInfo.mHardwareRenderer != null &&
+                                mSurface != null && mSurface.isValid()) {
+                            mFullRedrawNeeded = true;
                             try {
-                                if (!sWindowSession.outOfMemory(mWindow)) {
-                                    Slog.w(TAG, "No processes killed for memory; killing self");
-                                    Process.killProcess(Process.myPid());
+                                mAttachInfo.mHardwareRenderer.initializeIfNeeded(mWidth, mHeight,
+                                        mHolder);
+                            } catch (Surface.OutOfResourcesException e) {
+                                Log.e(TAG, "OutOfResourcesException locking surface", e);
+                                try {
+                                    if (!sWindowSession.outOfMemory(mWindow)) {
+                                        Slog.w(TAG, "No processes killed for memory; killing self");
+                                        Process.killProcess(Process.myPid());
+                                    }
+                                } catch (RemoteException ex) {
                                 }
-                            } catch (RemoteException ex) {
+                                // Retry in a bit.
+                                sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
+                                return;
                             }
-                            // Retry in a bit.
-                            sendMessageDelayed(obtainMessage(msg.what, msg.arg1, msg.arg2), 500);
-                            return;
                         }
                     }
-                }
 
-                mLastWasImTarget = WindowManager.LayoutParams
-                        .mayUseInputMethod(mWindowAttributes.flags);
+                    mLastWasImTarget = WindowManager.LayoutParams
+                            .mayUseInputMethod(mWindowAttributes.flags);
 
-                InputMethodManager imm = InputMethodManager.peekInstance();
-                if (mView != null) {
-                    if (hasWindowFocus && imm != null && mLastWasImTarget) {
-                        imm.startGettingWindowFocus(mView);
+                    InputMethodManager imm = InputMethodManager.peekInstance();
+                    if (mView != null) {
+                        if (hasWindowFocus && imm != null && mLastWasImTarget) {
+                            imm.startGettingWindowFocus(mView);
+                        }
+                        mAttachInfo.mKeyDispatchState.reset();
+                        mView.dispatchWindowFocusChanged(hasWindowFocus);
                     }
-                    mAttachInfo.mKeyDispatchState.reset();
-                    mView.dispatchWindowFocusChanged(hasWindowFocus);
-                }
 
-                // Note: must be done after the focus change callbacks,
-                // so all of the view state is set up correctly.
-                if (hasWindowFocus) {
-                    if (imm != null && mLastWasImTarget) {
-                        imm.onWindowFocus(mView, mView.findFocus(),
-                                mWindowAttributes.softInputMode,
-                                !mHasHadWindowFocus, mWindowAttributes.flags);
-                    }
-                    // Clear the forward bit.  We can just do this directly, since
-                    // the window manager doesn't care about it.
-                    mWindowAttributes.softInputMode &=
-                            ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
-                    ((WindowManager.LayoutParams)mView.getLayoutParams())
-                            .softInputMode &=
+                    // Note: must be done after the focus change callbacks,
+                    // so all of the view state is set up correctly.
+                    if (hasWindowFocus) {
+                        if (imm != null && mLastWasImTarget) {
+                            imm.onWindowFocus(mView, mView.findFocus(),
+                                    mWindowAttributes.softInputMode,
+                                    !mHasHadWindowFocus, mWindowAttributes.flags);
+                        }
+                        // Clear the forward bit.  We can just do this directly, since
+                        // the window manager doesn't care about it.
+                        mWindowAttributes.softInputMode &=
                                 ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
-                    mHasHadWindowFocus = true;
-                }
+                        ((WindowManager.LayoutParams)mView.getLayoutParams())
+                                .softInputMode &=
+                                    ~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
+                        mHasHadWindowFocus = true;
+                    }
 
-                if (hasWindowFocus && mView != null) {
-                    sendAccessibilityEvents();
+                    if (hasWindowFocus && mView != null && mAccessibilityManager.isEnabled()) {
+                        mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                    }
                 }
+            } break;
+            case MSG_DIE:
+                doDie();
+                break;
+            case MSG_DISPATCH_KEY: {
+                KeyEvent event = (KeyEvent)msg.obj;
+                enqueueInputEvent(event, null, 0, true);
+            } break;
+            case MSG_DISPATCH_KEY_FROM_IME: {
+                if (LOCAL_LOGV) Log.v(
+                    TAG, "Dispatching key "
+                    + msg.obj + " from IME to " + mView);
+                KeyEvent event = (KeyEvent)msg.obj;
+                if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
+                    // The IME is trying to say this event is from the
+                    // system!  Bad bad bad!
+                    //noinspection UnusedAssignment
+                    event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
+                }
+                enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
+            } break;
+            case MSG_FINISH_INPUT_CONNECTION: {
+                InputMethodManager imm = InputMethodManager.peekInstance();
+                if (imm != null) {
+                    imm.reportFinishInputConnection((InputConnection)msg.obj);
+                }
+            } break;
+            case MSG_CHECK_FOCUS: {
+                InputMethodManager imm = InputMethodManager.peekInstance();
+                if (imm != null) {
+                    imm.checkFocus();
+                }
+            } break;
+            case MSG_CLOSE_SYSTEM_DIALOGS: {
+                if (mView != null) {
+                    mView.onCloseSystemDialogs((String)msg.obj);
+                }
+            } break;
+            case MSG_DISPATCH_DRAG_EVENT:
+            case MSG_DISPATCH_DRAG_LOCATION_EVENT: {
+                DragEvent event = (DragEvent)msg.obj;
+                event.mLocalState = mLocalDragState;    // only present when this app called startDrag()
+                handleDragEvent(event);
+            } break;
+            case MSG_DISPATCH_SYSTEM_UI_VISIBILITY: {
+                handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
+            } break;
+            case MSG_UPDATE_CONFIGURATION: {
+                Configuration config = (Configuration)msg.obj;
+                if (config.isOtherSeqNewer(mLastConfiguration)) {
+                    config = mLastConfiguration;
+                }
+                updateConfiguration(config, false);
+            } break;
+            case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
+                if (mView != null) {
+                    getAccessibilityInteractionController()
+                        .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
+                }
+            } break;
+            case MSG_PERFORM_ACCESSIBILITY_ACTION: {
+                if (mView != null) {
+                    getAccessibilityInteractionController()
+                        .perfromAccessibilityActionUiThread(msg);
+                }
+            } break;
+            case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
+                if (mView != null) {
+                    getAccessibilityInteractionController()
+                        .findAccessibilityNodeInfoByViewIdUiThread(msg);
+                }
+            } break;
+            case MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
+                if (mView != null) {
+                    getAccessibilityInteractionController()
+                        .findAccessibilityNodeInfosByTextUiThread(msg);
+                }
+            } break;
             }
-        } break;
-        case DIE:
-            doDie();
-            break;
-        case DISPATCH_KEY: {
-            KeyEvent event = (KeyEvent)msg.obj;
-            enqueueInputEvent(event, null, 0, true);
-        } break;
-        case DISPATCH_KEY_FROM_IME: {
-            if (LOCAL_LOGV) Log.v(
-                TAG, "Dispatching key "
-                + msg.obj + " from IME to " + mView);
-            KeyEvent event = (KeyEvent)msg.obj;
-            if ((event.getFlags()&KeyEvent.FLAG_FROM_SYSTEM) != 0) {
-                // The IME is trying to say this event is from the
-                // system!  Bad bad bad!
-                //noinspection UnusedAssignment
-                event = KeyEvent.changeFlags(event, event.getFlags() & ~KeyEvent.FLAG_FROM_SYSTEM);
-            }
-            enqueueInputEvent(event, null, QueuedInputEvent.FLAG_DELIVER_POST_IME, true);
-        } break;
-        case FINISH_INPUT_CONNECTION: {
-            InputMethodManager imm = InputMethodManager.peekInstance();
-            if (imm != null) {
-                imm.reportFinishInputConnection((InputConnection)msg.obj);
-            }
-        } break;
-        case CHECK_FOCUS: {
-            InputMethodManager imm = InputMethodManager.peekInstance();
-            if (imm != null) {
-                imm.checkFocus();
-            }
-        } break;
-        case CLOSE_SYSTEM_DIALOGS: {
-            if (mView != null) {
-                mView.onCloseSystemDialogs((String)msg.obj);
-            }
-        } break;
-        case DISPATCH_DRAG_EVENT:
-        case DISPATCH_DRAG_LOCATION_EVENT: {
-            DragEvent event = (DragEvent)msg.obj;
-            event.mLocalState = mLocalDragState;    // only present when this app called startDrag()
-            handleDragEvent(event);
-        } break;
-        case DISPATCH_SYSTEM_UI_VISIBILITY: {
-            handleDispatchSystemUiVisibilityChanged((SystemUiVisibilityInfo)msg.obj);
-        } break;
-        case UPDATE_CONFIGURATION: {
-            Configuration config = (Configuration)msg.obj;
-            if (config.isOtherSeqNewer(mLastConfiguration)) {
-                config = mLastConfiguration;
-            }
-            updateConfiguration(config, false);
-        } break;
-        case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID: {
-            if (mView != null) {
-                getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfoByAccessibilityIdUiThread(msg);
-            }
-        } break;
-        case DO_PERFORM_ACCESSIBILITY_ACTION: {
-            if (mView != null) {
-                getAccessibilityInteractionController()
-                    .perfromAccessibilityActionUiThread(msg);
-            }
-        } break;
-        case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID: {
-            if (mView != null) {
-                getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfoByViewIdUiThread(msg);
-            }
-        } break;
-        case DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT: {
-            if (mView != null) {
-                getAccessibilityInteractionController()
-                    .findAccessibilityNodeInfosByTextUiThread(msg);
-            }
-        } break;
         }
     }
+    final ViewRootHandler mHandler = new ViewRootHandler();
 
     /**
      * Something in the current window tells us we need to change the touch mode.  For
@@ -3684,7 +3699,7 @@
         if (immediate) {
             doDie();
         } else {
-            sendEmptyMessage(DIE);
+            mHandler.sendEmptyMessage(MSG_DIE);
         }
     }
 
@@ -3721,8 +3736,8 @@
     }
 
     public void requestUpdateConfiguration(Configuration config) {
-        Message msg = obtainMessage(UPDATE_CONFIGURATION, config);
-        sendMessage(msg);
+        Message msg = mHandler.obtainMessage(MSG_UPDATE_CONFIGURATION, config);
+        mHandler.sendMessage(msg);
     }
 
     private void destroyHardwareRenderer() {
@@ -3734,10 +3749,15 @@
     }
 
     void dispatchImeFinishedEvent(int seq, boolean handled) {
-        Message msg = obtainMessage(IME_FINISHED_EVENT);
+        Message msg = mHandler.obtainMessage(MSG_IME_FINISHED_EVENT);
         msg.arg1 = seq;
         msg.arg2 = handled ? 1 : 0;
-        sendMessage(msg);
+        mHandler.sendMessage(msg);
+    }
+
+    public void dispatchFinishInputConnection(InputConnection connection) {
+        Message msg = mHandler.obtainMessage(MSG_FINISH_INPUT_CONNECTION, connection);
+        mHandler.sendMessage(msg);
     }
 
     public void dispatchResized(int w, int h, Rect coveredInsets,
@@ -3746,7 +3766,7 @@
                 + " h=" + h + " coveredInsets=" + coveredInsets.toShortString()
                 + " visibleInsets=" + visibleInsets.toShortString()
                 + " reportDraw=" + reportDraw);
-        Message msg = obtainMessage(reportDraw ? RESIZED_REPORT :RESIZED);
+        Message msg = mHandler.obtainMessage(reportDraw ? MSG_RESIZED_REPORT :MSG_RESIZED);
         if (mTranslator != null) {
             mTranslator.translateRectInScreenToAppWindow(coveredInsets);
             mTranslator.translateRectInScreenToAppWindow(visibleInsets);
@@ -3760,7 +3780,7 @@
         ri.visibleInsets = new Rect(visibleInsets);
         ri.newConfig = newConfig;
         msg.obj = ri;
-        sendMessage(msg);
+        mHandler.sendMessage(msg);
     }
 
     /**
@@ -3857,7 +3877,7 @@
     private void scheduleProcessInputEvents() {
         if (!mProcessInputEventsScheduled) {
             mProcessInputEventsScheduled = true;
-            sendEmptyMessage(DO_PROCESS_INPUT_EVENTS);
+            mHandler.sendEmptyMessage(MSG_PROCESS_INPUT_EVENTS);
         }
     }
 
@@ -3874,7 +3894,7 @@
         // so we can clear the pending flag immediately.
         if (mProcessInputEventsScheduled) {
             mProcessInputEventsScheduled = false;
-            removeMessages(DO_PROCESS_INPUT_EVENTS);
+            mHandler.removeMessages(MSG_PROCESS_INPUT_EVENTS);
         }
     }
 
@@ -3960,47 +3980,69 @@
     }
     WindowInputEventReceiver mInputEventReceiver;
 
+    public void dispatchInvalidateDelayed(View view, long delayMilliseconds) {
+        Message msg = mHandler.obtainMessage(MSG_INVALIDATE, view);
+        mHandler.sendMessageDelayed(msg, delayMilliseconds);
+    }
+
+    public void cancelInvalidate(View view) {
+        mHandler.removeMessages(MSG_INVALIDATE, view);
+    }
+
+    public void dispatchInvalidateRectDelayed(AttachInfo.InvalidateInfo info,
+            long delayMilliseconds) {
+        final Message msg = mHandler.obtainMessage(MSG_INVALIDATE_RECT, info);
+        mHandler.sendMessageDelayed(msg, delayMilliseconds);
+    }
+
     public void dispatchKey(KeyEvent event) {
-        Message msg = obtainMessage(DISPATCH_KEY, event);
-        sendMessage(msg);
+        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY, event);
+        msg.setAsynchronous(true);
+        mHandler.sendMessage(msg);
+    }
+
+    public void dispatchKeyFromIme(KeyEvent event) {
+        Message msg = mHandler.obtainMessage(MSG_DISPATCH_KEY_FROM_IME, event);
+        msg.setAsynchronous(true);
+        mHandler.sendMessage(msg);
     }
 
     public void dispatchAppVisibility(boolean visible) {
-        Message msg = obtainMessage(DISPATCH_APP_VISIBILITY);
+        Message msg = mHandler.obtainMessage(MSG_DISPATCH_APP_VISIBILITY);
         msg.arg1 = visible ? 1 : 0;
-        sendMessage(msg);
+        mHandler.sendMessage(msg);
     }
 
     public void dispatchGetNewSurface() {
-        Message msg = obtainMessage(DISPATCH_GET_NEW_SURFACE);
-        sendMessage(msg);
+        Message msg = mHandler.obtainMessage(MSG_DISPATCH_GET_NEW_SURFACE);
+        mHandler.sendMessage(msg);
     }
 
     public void windowFocusChanged(boolean hasFocus, boolean inTouchMode) {
         Message msg = Message.obtain();
-        msg.what = WINDOW_FOCUS_CHANGED;
+        msg.what = MSG_WINDOW_FOCUS_CHANGED;
         msg.arg1 = hasFocus ? 1 : 0;
         msg.arg2 = inTouchMode ? 1 : 0;
-        sendMessage(msg);
+        mHandler.sendMessage(msg);
     }
 
     public void dispatchCloseSystemDialogs(String reason) {
         Message msg = Message.obtain();
-        msg.what = CLOSE_SYSTEM_DIALOGS;
+        msg.what = MSG_CLOSE_SYSTEM_DIALOGS;
         msg.obj = reason;
-        sendMessage(msg);
+        mHandler.sendMessage(msg);
     }
 
     public void dispatchDragEvent(DragEvent event) {
         final int what;
         if (event.getAction() == DragEvent.ACTION_DRAG_LOCATION) {
-            what = DISPATCH_DRAG_LOCATION_EVENT;
-            removeMessages(what);
+            what = MSG_DISPATCH_DRAG_LOCATION_EVENT;
+            mHandler.removeMessages(what);
         } else {
-            what = DISPATCH_DRAG_EVENT;
+            what = MSG_DISPATCH_DRAG_EVENT;
         }
-        Message msg = obtainMessage(what, event);
-        sendMessage(msg);
+        Message msg = mHandler.obtainMessage(what, event);
+        mHandler.sendMessage(msg);
     }
 
     public void dispatchSystemUiVisibilityChanged(int seq, int globalVisibility,
@@ -4010,21 +4052,13 @@
         args.globalVisibility = globalVisibility;
         args.localValue = localValue;
         args.localChanges = localChanges;
-        sendMessage(obtainMessage(DISPATCH_SYSTEM_UI_VISIBILITY, args));
+        mHandler.sendMessage(mHandler.obtainMessage(MSG_DISPATCH_SYSTEM_UI_VISIBILITY, args));
     }
 
-    /**
-     * The window is getting focus so if there is anything focused/selected
-     * send an {@link AccessibilityEvent} to announce that.
-     */
-    private void sendAccessibilityEvents() {
-        if (!mAccessibilityManager.isEnabled()) {
-            return;
-        }
-        mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-        View focusedView = mView.findFocus();
-        if (focusedView != null && focusedView != mView) {
-            focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+    public void dispatchCheckFocus() {
+        if (!mHandler.hasMessages(MSG_CHECK_FOCUS)) {
+            // This will result in a call to checkFocus() below.
+            mHandler.sendEmptyMessage(MSG_CHECK_FOCUS);
         }
     }
 
@@ -4041,7 +4075,7 @@
         }
         if (!mSendWindowContentChangedAccessibilityEvent.mIsPending) {
             mSendWindowContentChangedAccessibilityEvent.mIsPending = true;
-            postDelayed(mSendWindowContentChangedAccessibilityEvent,
+            mHandler.postDelayed(mSendWindowContentChangedAccessibilityEvent,
                     ViewConfiguration.getSendRecurringAccessibilityEventsInterval());
         }
     }
@@ -4052,7 +4086,7 @@
      */
     private void removeSendWindowContentChangedCallback() {
         if (mSendWindowContentChangedAccessibilityEvent != null) {
-            removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
+            mHandler.removeCallbacks(mSendWindowContentChangedAccessibilityEvent);
         }
     }
 
@@ -4095,6 +4129,10 @@
         return scrollToRectOrFocus(rectangle, immediate);
     }
 
+    public void childHasTransientStateChanged(View child, boolean hasTransientState) {
+        // Do nothing.
+    }
+
     class TakenSurfaceHolder extends BaseSurfaceHolder {
         @Override
         public boolean onAllowLockCanvas() {
@@ -4512,6 +4550,9 @@
     }
 
     /**
+     * The run queue is used to enqueue pending work from Views when no Handler is
+     * attached.  The work is executed during the next call to performTraversals on
+     * the thread.
      * @hide
      */
     static final class RunQueue {
@@ -4590,24 +4631,35 @@
         public void onAccessibilityStateChanged(boolean enabled) {
             if (enabled) {
                 ensureConnection();
+                if (mAttachInfo != null && mAttachInfo.mHasWindowFocus) {
+                    mView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                    View focusedView = mView.findFocus();
+                    if (focusedView != null && focusedView != mView) {
+                        focusedView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+                    }
+                }
             } else {
                 ensureNoConnection();
             }
         }
 
         public void ensureConnection() {
-            final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
-            if (!registered) {
-                mAttachInfo.mAccessibilityWindowId =
-                    mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
-                            new AccessibilityInteractionConnection(ViewRootImpl.this));
+            if (mAttachInfo != null) {
+                final boolean registered =
+                    mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
+                if (!registered) {
+                    mAttachInfo.mAccessibilityWindowId =
+                        mAccessibilityManager.addAccessibilityInteractionConnection(mWindow,
+                                new AccessibilityInteractionConnection(ViewRootImpl.this));
+                }
             }
         }
 
         public void ensureNoConnection() {
-            final boolean registered = mAttachInfo.mAccessibilityWindowId != View.NO_ID;
+            final boolean registered =
+                mAttachInfo.mAccessibilityWindowId != AccessibilityNodeInfo.UNDEFINED;
             if (registered) {
-                mAttachInfo.mAccessibilityWindowId = View.NO_ID;
+                mAttachInfo.mAccessibilityWindowId = AccessibilityNodeInfo.UNDEFINED;
                 mAccessibilityManager.removeAccessibilityInteractionConnection(mWindow);
             }
         }
@@ -4770,8 +4822,8 @@
                 long accessibilityNodeId, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
                 long interrogatingTid) {
-            Message message = Message.obtain();
-            message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
+            Message message = mHandler.obtainMessage();
+            message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_ACCESSIBILITY_ID;
             message.arg1 = interrogatingPid;
             SomeArgs args = mPool.acquire();
             args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
@@ -4785,11 +4837,10 @@
             // client can handle the message to generate the result.
             if (interrogatingPid == Process.myPid()
                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                message.setTarget(ViewRootImpl.this);
                 AccessibilityInteractionClient.getInstanceForThread(
                         interrogatingTid).setSameThreadMessage(message);
             } else {
-                sendMessage(message);
+                mHandler.sendMessage(message);
             }
         }
 
@@ -4805,14 +4856,21 @@
             List<AccessibilityNodeInfo> infos = mTempAccessibilityNodeInfoList;
             infos.clear();
             try {
-                View target = findViewByAccessibilityId(accessibilityViewId);
-                if (target != null && target.getVisibility() == View.VISIBLE) {
-                    AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
-                    if (provider != null) {
-                        infos.add(provider.createAccessibilityNodeInfo(virtualDescendantId));
-                    } else if (virtualDescendantId == View.NO_ID) {
-                        getAccessibilityPrefetchStrategy().prefetchAccessibilityNodeInfos(
-                                interrogatingPid, target, infos);
+                if (accessibilityViewId == AccessibilityNodeInfo.UNDEFINED) {
+                    View target = ViewRootImpl.this.mView;
+                    if (target != null && target.getVisibility() == View.VISIBLE) {
+                        infos.add(target.createAccessibilityNodeInfo());
+                    }
+                } else {
+                    View target = findViewByAccessibilityId(accessibilityViewId);
+                    if (target != null && target.getVisibility() == View.VISIBLE) {
+                        AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
+                        if (provider != null) {
+                            infos.add(provider.createAccessibilityNodeInfo(virtualDescendantId));
+                        } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED) {
+                            getAccessibilityPrefetchStrategy().prefetchAccessibilityNodeInfos(
+                                    interrogatingPid, target, infos);
+                        }
                     }
                 }
             } finally {
@@ -4828,8 +4886,8 @@
         public void findAccessibilityNodeInfoByViewIdClientThread(long accessibilityNodeId,
                 int viewId, int interactionId, IAccessibilityInteractionConnectionCallback callback,
                 int interrogatingPid, long interrogatingTid) {
-            Message message = Message.obtain();
-            message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
+            Message message = mHandler.obtainMessage();
+            message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_VIEW_ID;
             message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
             SomeArgs args = mPool.acquire();
             args.argi1 = viewId;
@@ -4842,11 +4900,10 @@
             // client can handle the message to generate the result.
             if (interrogatingPid == Process.myPid()
                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                message.setTarget(ViewRootImpl.this);
                 AccessibilityInteractionClient.getInstanceForThread(
                         interrogatingTid).setSameThreadMessage(message);
             } else {
-                sendMessage(message);
+                mHandler.sendMessage(message);
             }
         }
 
@@ -4861,7 +4918,7 @@
             AccessibilityNodeInfo info = null;
             try {
                 View root = null;
-                if (accessibilityViewId != View.NO_ID) {
+                if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
                     root = findViewByAccessibilityId(accessibilityViewId);
                 } else {
                     root = ViewRootImpl.this.mView;
@@ -4885,8 +4942,8 @@
                 String text, int interactionId,
                 IAccessibilityInteractionConnectionCallback callback, int interrogatingPid,
                 long interrogatingTid) {
-            Message message = Message.obtain();
-            message.what = DO_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
+            Message message = mHandler.obtainMessage();
+            message.what = MSG_FIND_ACCESSIBLITY_NODE_INFO_BY_TEXT;
             SomeArgs args = mPool.acquire();
             args.arg1 = text;
             args.argi1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
@@ -4900,11 +4957,10 @@
             // client can handle the message to generate the result.
             if (interrogatingPid == Process.myPid()
                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                message.setTarget(ViewRootImpl.this);
                 AccessibilityInteractionClient.getInstanceForThread(
                         interrogatingTid).setSameThreadMessage(message);
             } else {
-                sendMessage(message);
+                mHandler.sendMessage(message);
             }
         }
 
@@ -4920,7 +4976,7 @@
             List<AccessibilityNodeInfo> infos = null;
             try {
                 View target;
-                if (accessibilityViewId != View.NO_ID) {
+                if (accessibilityViewId != AccessibilityNodeInfo.UNDEFINED) {
                     target = findViewByAccessibilityId(accessibilityViewId);
                 } else {
                     target = ViewRootImpl.this.mView;
@@ -4930,7 +4986,7 @@
                     if (provider != null) {
                         infos = provider.findAccessibilityNodeInfosByText(text,
                                 virtualDescendantId);
-                    } else if (virtualDescendantId == View.NO_ID) {
+                    } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED) {
                         ArrayList<View> foundViews = mAttachInfo.mFocusablesTempList;
                         foundViews.clear();
                         target.findViewsWithText(foundViews, text, View.FIND_VIEWS_WITH_TEXT
@@ -4971,8 +5027,8 @@
         public void performAccessibilityActionClientThread(long accessibilityNodeId, int action,
                 int interactionId, IAccessibilityInteractionConnectionCallback callback,
                 int interogatingPid, long interrogatingTid) {
-            Message message = Message.obtain();
-            message.what = DO_PERFORM_ACCESSIBILITY_ACTION;
+            Message message = mHandler.obtainMessage();
+            message.what = MSG_PERFORM_ACCESSIBILITY_ACTION;
             message.arg1 = AccessibilityNodeInfo.getAccessibilityViewId(accessibilityNodeId);
             message.arg2 = AccessibilityNodeInfo.getVirtualDescendantId(accessibilityNodeId);
             SomeArgs args = mPool.acquire();
@@ -4986,11 +5042,10 @@
             // client can handle the message to generate the result.
             if (interogatingPid == Process.myPid()
                     && interrogatingTid == Looper.getMainLooper().getThread().getId()) {
-                message.setTarget(ViewRootImpl.this);
                 AccessibilityInteractionClient.getInstanceForThread(
                         interrogatingTid).setSameThreadMessage(message);
             } else {
-                sendMessage(message);
+                mHandler.sendMessage(message);
             }
         }
 
@@ -5011,7 +5066,7 @@
                     if (provider != null) {
                         succeeded = provider.performAccessibilityAction(action,
                                 virtualDescendantId);
-                    } else if (virtualDescendantId == View.NO_ID) {
+                    } else if (virtualDescendantId == AccessibilityNodeInfo.UNDEFINED) {
                         switch (action) {
                             case AccessibilityNodeInfo.ACTION_FOCUS: {
                                 if (!target.hasFocus()) {
@@ -5119,7 +5174,7 @@
         private void addAndCacheNotCachedNodeInfo(long interrogatingPid,
                 View view, List<AccessibilityNodeInfo> outInfos) {
             final long accessibilityNodeId = AccessibilityNodeInfo.makeNodeId(
-                    view.getAccessibilityViewId(), View.NO_ID);
+                    view.getAccessibilityViewId(), AccessibilityNodeInfo.UNDEFINED);
             AccessibilityNodeInfoCache cache = getCacheForInterrogatingPid(interrogatingPid);
             if (!cache.containsKey(accessibilityNodeId)) {
                 // Account for the ids of the fetched infos. The infos will be
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 072fdd8..105c010 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -153,10 +153,12 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
-     * @param accessibilityNodeId A unique node accessibility id
-     *     (accessibility view and virtual descendant id).
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
      */
     public AccessibilityNodeInfo findAccessibilityNodeInfoByAccessibilityId(int connectionId,
@@ -164,7 +166,8 @@
         try {
             IAccessibilityServiceConnection connection = getConnection(connectionId);
             if (connection != null) {
-                AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(accessibilityNodeId); 
+                AccessibilityNodeInfo cachedInfo = sAccessibilityNodeInfoCache.get(
+                        accessibilityNodeId);
                 if (cachedInfo != null) {
                     return cachedInfo;
                 }
@@ -176,7 +179,7 @@
                 if (windowScale > 0) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale);
                     if (infos != null && !infos.isEmpty()) {
                         return infos.get(0);
                     }
@@ -202,10 +205,11 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
-     * @param accessibilityNodeId A unique view id from where to start the search. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
      *     to start from the root.
      * @param viewId The id of the view.
      * @return An {@link AccessibilityNodeInfo} if found, null otherwise.
@@ -224,7 +228,7 @@
                 if (windowScale > 0) {
                     AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
                             interactionId);
-                    finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
+                    finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale);
                     return info;
                 }
             } else {
@@ -249,10 +253,12 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
-     * @param accessibilityNodeId A unique view id from where to start the search. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ROOT_NODE_ID}
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
      * @param text The searched text.
      * @return A list of found {@link AccessibilityNodeInfo}s.
      */
@@ -269,7 +275,7 @@
                 if (windowScale > 0) {
                     List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
                             interactionId);
-                    finalizeAccessibilityNodeInfos(infos, connectionId, windowScale);
+                    finalizeAndCacheAccessibilityNodeInfos(infos, connectionId, windowScale);
                     return infos;
                 }
             } else {
@@ -291,9 +297,12 @@
      *
      * @param connectionId The id of a connection for interacting with the system.
      * @param accessibilityWindowId A unique window id. Use
-     *     {@link com.android.server.accessibility.AccessibilityManagerService#ACTIVE_WINDOW_ID}
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ACTIVE_WINDOW_ID}
      *     to query the currently active window.
-     * @param accessibilityNodeId A unique node id (accessibility and virtual descendant id).
+     * @param accessibilityNodeId A unique view id or virtual descendant id from
+     *     where to start the search. Use
+     *     {@link android.view.accessibility.AccessibilityNodeInfo#ROOT_NODE_ID}
+     *     to start from the root.
      * @param action The action to perform.
      * @return Whether the action was performed.
      */
@@ -323,16 +332,10 @@
     }
 
     public void clearCache() {
-        if (DEBUG) {
-            Log.w(LOG_TAG, "clearCache()");
-        }
         sAccessibilityNodeInfoCache.clear();
     }
 
     public void removeCachedNode(long accessibilityNodeId) {
-        if (DEBUG) {
-            Log.w(LOG_TAG, "removeCachedNode(" + accessibilityNodeId +")");
-        }
         sAccessibilityNodeInfoCache.remove(accessibilityNodeId);
     }
 
@@ -364,9 +367,6 @@
             if (interactionId > mInteractionId) {
                 mFindAccessibilityNodeInfoResult = info;
                 mInteractionId = interactionId;
-                if (info != null) {
-                    sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
-                }
             }
             mInstanceLock.notifyAll();
         }
@@ -404,11 +404,6 @@
                     mFindAccessibilityNodeInfosResult = infos;
                 }
                 mInteractionId = interactionId;
-                final int infoCount = infos.size();
-                for (int i = 0; i < infoCount; i ++) {
-                    AccessibilityNodeInfo info = infos.get(i);
-                    sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
-                }
             }
             mInstanceLock.notifyAll();
         }
@@ -513,12 +508,13 @@
      * @param connectionId The id of the connection to the system.
      * @param windowScale The source window compatibility scale.
      */
-    private void finalizeAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId,
+    private void finalizeAndCacheAccessibilityNodeInfo(AccessibilityNodeInfo info, int connectionId,
             float windowScale) {
         if (info != null) {
             applyCompatibilityScaleIfNeeded(info, windowScale);
             info.setConnectionId(connectionId);
             info.setSealed(true);
+            sAccessibilityNodeInfoCache.put(info.getSourceNodeId(), info);
         }
     }
 
@@ -529,13 +525,13 @@
      * @param connectionId The id of the connection to the system.
      * @param windowScale The source window compatibility scale.
      */
-    private void finalizeAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
+    private void finalizeAndCacheAccessibilityNodeInfos(List<AccessibilityNodeInfo> infos,
             int connectionId, float windowScale) {
         if (infos != null) {
             final int infosCount = infos.size();
             for (int i = 0; i < infosCount; i++) {
                 AccessibilityNodeInfo info = infos.get(i);
-                finalizeAccessibilityNodeInfo(info, connectionId, windowScale);
+                finalizeAndCacheAccessibilityNodeInfo(info, connectionId, windowScale);
             }
         }
     }
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index d7d6792..84ad268 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -52,7 +52,14 @@
 
     private static final boolean DEBUG = false;
 
-    private static final int UNDEFINED = -1;
+    /** @hide */
+    public static final int UNDEFINED = -1;
+
+    /** @hide */
+    public static final long ROOT_NODE_ID = makeNodeId(UNDEFINED, UNDEFINED);
+
+    /** @hide */
+    public static final int ACTIVE_WINDOW_ID = UNDEFINED;
 
     // Actions.
 
@@ -162,8 +169,8 @@
 
     // Data.
     private int mWindowId = UNDEFINED;
-    private long mSourceNodeId = makeNodeId(UNDEFINED, UNDEFINED);
-    private long mParentNodeId = makeNodeId(UNDEFINED, UNDEFINED);
+    private long mSourceNodeId = ROOT_NODE_ID;
+    private long mParentNodeId = ROOT_NODE_ID;
 
     private int mBooleanProperties;
     private final Rect mBoundsInParent = new Rect();
@@ -1160,8 +1167,8 @@
      */
     private void clear() {
         mSealed = false;
-        mSourceNodeId = makeNodeId(UNDEFINED, UNDEFINED);
-        mParentNodeId = makeNodeId(UNDEFINED, UNDEFINED);
+        mSourceNodeId = ROOT_NODE_ID;
+        mParentNodeId = ROOT_NODE_ID;
         mWindowId = UNDEFINED;
         mConnectionId = UNDEFINED;
         mChildIds.clear();
diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java
index bd02d62..89aba3c 100644
--- a/core/java/android/view/inputmethod/BaseInputConnection.java
+++ b/core/java/android/view/inputmethod/BaseInputConnection.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.os.Bundle;
-import android.os.Handler;
 import android.os.SystemClock;
 import android.text.Editable;
 import android.text.NoCopySpan;
@@ -497,15 +496,14 @@
      */
     public boolean sendKeyEvent(KeyEvent event) {
         synchronized (mIMM.mH) {
-            Handler h = mTargetView != null ? mTargetView.getHandler() : null;
-            if (h == null) {
+            ViewRootImpl viewRootImpl = mTargetView != null ? mTargetView.getViewRootImpl() : null;
+            if (viewRootImpl == null) {
                 if (mIMM.mServedView != null) {
-                    h = mIMM.mServedView.getHandler();
+                    viewRootImpl = mIMM.mServedView.getViewRootImpl();
                 }
             }
-            if (h != null) {
-                h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
-                        event));
+            if (viewRootImpl != null) {
+                viewRootImpl.dispatchKeyFromIme(event);
             }
         }
         return false;
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 7171b58..c51d244 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -336,6 +336,7 @@
                 }
                 case MSG_UNBIND: {
                     final int sequence = msg.arg1;
+                    boolean startInput = false;
                     synchronized (mH) {
                         if (mBindSequence == sequence) {
                             if (false) {
@@ -355,7 +356,12 @@
                             if (mServedView != null && mServedView.isFocused()) {
                                 mServedConnecting = true;
                             }
+                            if (mActive) {
+                                startInput = true;
+                            }
                         }
+                    }
+                    if (startInput) {
                         startInputInner();
                     }
                     return;
@@ -669,11 +675,10 @@
             // longer the input target, so it can reset its state.  Schedule
             // this call on its window's Handler so it will be on the correct
             // thread and outside of our lock.
-            Handler vh = mServedView.getHandler();
-            if (vh != null) {
+            ViewRootImpl viewRootImpl = mServedView.getViewRootImpl();
+            if (viewRootImpl != null) {
                 // This will result in a call to reportFinishInputConnection() below.
-                vh.sendMessage(vh.obtainMessage(ViewRootImpl.FINISH_INPUT_CONNECTION,
-                        mServedInputConnection));
+                viewRootImpl.dispatchFinishInputConnection(mServedInputConnection);
             }
         }
     }
@@ -1124,31 +1129,36 @@
     }
 
     static void scheduleCheckFocusLocked(View view) {
-        Handler vh = view.getHandler();
-        if (vh != null && !vh.hasMessages(ViewRootImpl.CHECK_FOCUS)) {
-            // This will result in a call to checkFocus() below.
-            vh.sendMessage(vh.obtainMessage(ViewRootImpl.CHECK_FOCUS));
+        ViewRootImpl viewRootImpl = view.getViewRootImpl();
+        if (viewRootImpl != null) {
+            viewRootImpl.dispatchCheckFocus();
         }
     }
-    
+
     /**
      * @hide
      */
     public void checkFocus() {
+        if (checkFocusNoStartInput()) {
+            startInputInner();
+        }
+    }
+
+    private boolean checkFocusNoStartInput() {
         // This is called a lot, so short-circuit before locking.
         if (mServedView == mNextServedView && !mNextServedNeedsStart) {
-            return;
+            return false;
         }
 
         InputConnection ic = null;
         synchronized (mH) {
             if (mServedView == mNextServedView && !mNextServedNeedsStart) {
-                return;
+                return false;
             }
             if (DEBUG) Log.v(TAG, "checkFocus: view=" + mServedView
                     + " next=" + mNextServedView
                     + " restart=" + mNextServedNeedsStart);
-            
+
             mNextServedNeedsStart = false;
             if (mNextServedView == null) {
                 finishInputLocked();
@@ -1156,22 +1166,22 @@
                 // but no longer do.  We should make sure the input method is
                 // no longer shown, since it serves no purpose.
                 closeCurrentInput();
-                return;
+                return false;
             }
-            
+
             ic = mServedInputConnection;
-            
+
             mServedView = mNextServedView;
             mCurrentTextBoxAttribute = null;
             mCompletions = null;
             mServedConnecting = true;
         }
-        
+
         if (ic != null) {
             ic.finishComposingText();
         }
-        
-        startInputInner();
+
+        return true;
     }
     
     void closeCurrentInput() {
@@ -1200,7 +1210,7 @@
             focusInLocked(focusedView != null ? focusedView : rootView);
         }
         
-        checkFocus();
+        boolean startInput = checkFocusNoStartInput();
         
         synchronized (mH) {
             try {
@@ -1212,6 +1222,10 @@
             } catch (RemoteException e) {
             }
         }
+
+        if (startInput) {
+            startInputInner();
+        }
     }
     
     /** @hide */
diff --git a/core/java/android/view/textservice/SentenceSuggestionsInfo.aidl b/core/java/android/view/textservice/SentenceSuggestionsInfo.aidl
new file mode 100644
index 0000000..d0b6ba6
--- /dev/null
+++ b/core/java/android/view/textservice/SentenceSuggestionsInfo.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textservice;
+
+parcelable SentenceSuggestionsInfo;
diff --git a/core/java/android/view/textservice/SentenceSuggestionsInfo.java b/core/java/android/view/textservice/SentenceSuggestionsInfo.java
new file mode 100644
index 0000000..8d7c6cf
--- /dev/null
+++ b/core/java/android/view/textservice/SentenceSuggestionsInfo.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2012 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. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+
+package android.view.textservice;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ * This class contains a metadata of sentence level suggestions from the text service
+ */
+public final class SentenceSuggestionsInfo implements Parcelable {
+
+    private final SuggestionsInfo[] mSuggestionsInfos;
+    private final int[] mOffsets;
+    private final int[] mLengths;
+
+    /**
+     * Constructor.
+     * @param suggestionsInfos from the text service
+     * @param offsets the array of offsets of suggestions
+     * @param lengths the array of lengths of suggestions
+     */
+    public SentenceSuggestionsInfo(
+            SuggestionsInfo[] suggestionsInfos, int[] offsets, int[] lengths) {
+        if (suggestionsInfos == null || offsets == null || lengths == null) {
+            throw new NullPointerException();
+        }
+        if (suggestionsInfos.length != offsets.length || offsets.length != lengths.length) {
+            throw new IllegalArgumentException();
+        }
+        final int infoSize = suggestionsInfos.length;
+        mSuggestionsInfos = Arrays.copyOf(suggestionsInfos, infoSize);
+        mOffsets = Arrays.copyOf(offsets, infoSize);
+        mLengths = Arrays.copyOf(lengths, infoSize);
+    }
+
+    public SentenceSuggestionsInfo(Parcel source) {
+        final int infoSize = source.readInt();
+        mSuggestionsInfos = new SuggestionsInfo[infoSize];
+        source.readTypedArray(mSuggestionsInfos, SuggestionsInfo.CREATOR);
+        mOffsets = new int[mSuggestionsInfos.length];
+        source.readIntArray(mOffsets);
+        mLengths = new int[mSuggestionsInfos.length];
+        source.readIntArray(mLengths);
+    }
+
+    /**
+     * Used to package this object into a {@link Parcel}.
+     *
+     * @param dest The {@link Parcel} to be written.
+     * @param flags The flags used for parceling.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        final int infoSize = mSuggestionsInfos.length;
+        dest.writeInt(infoSize);
+        dest.writeTypedArray(mSuggestionsInfos, 0);
+        dest.writeIntArray(mOffsets);
+        dest.writeIntArray(mLengths);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /**
+     * @hide
+     */
+    public SuggestionsInfo getSuggestionsInfoAt(int i) {
+        if (i >= 0 && i < mSuggestionsInfos.length) {
+            return mSuggestionsInfos[i];
+        }
+        return null;
+    }
+
+    /**
+     * @hide
+     */
+    public int getOffsetAt(int i) {
+        if (i >= 0 && i < mOffsets.length) {
+            return mOffsets[i];
+        }
+        return -1;
+    }
+
+    /**
+     * @hide
+     */
+    public int getLengthAt(int i) {
+        if (i >= 0 && i < mLengths.length) {
+            return mLengths[i];
+        }
+        return -1;
+    }
+
+    /**
+     * Used to make this class parcelable.
+     */
+    public static final Parcelable.Creator<SentenceSuggestionsInfo> CREATOR
+            = new Parcelable.Creator<SentenceSuggestionsInfo>() {
+        @Override
+        public SentenceSuggestionsInfo createFromParcel(Parcel source) {
+            return new SentenceSuggestionsInfo(source);
+        }
+
+        @Override
+        public SentenceSuggestionsInfo[] newArray(int size) {
+            return new SentenceSuggestionsInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index f6418ce..3491a537 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -115,7 +115,7 @@
                     handleOnGetSuggestionsMultiple((SuggestionsInfo[]) msg.obj);
                     break;
                 case MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE:
-                    handleOnGetSuggestionsMultipleForSentence((SuggestionsInfo[]) msg.obj);
+                    handleOnGetSentenceSuggestionsMultiple((SentenceSuggestionsInfo[]) msg.obj);
                     break;
             }
         }
@@ -180,8 +180,8 @@
     /**
      * @hide
      */
-    public void getSuggestionsForSentence(TextInfo textInfo, int suggestionsLimit) {
-        mSpellCheckerSessionListenerImpl.getSuggestionsMultipleForSentence(
+    public void getSentenceSuggestions(TextInfo textInfo, int suggestionsLimit) {
+        mSpellCheckerSessionListenerImpl.getSentenceSuggestionsMultiple(
                 new TextInfo[] {textInfo}, suggestionsLimit);
     }
 
@@ -214,8 +214,8 @@
         mSpellCheckerSessionListener.onGetSuggestions(suggestionInfos);
     }
 
-    private void handleOnGetSuggestionsMultipleForSentence(SuggestionsInfo[] suggestionInfos) {
-        mSpellCheckerSessionListener.onGetSuggestionsForSentence(suggestionInfos);
+    private void handleOnGetSentenceSuggestionsMultiple(SentenceSuggestionsInfo[] suggestionInfos) {
+        mSpellCheckerSessionListener.onGetSentenceSuggestions(suggestionInfos);
     }
 
     private static class SpellCheckerSessionListenerImpl extends ISpellCheckerSessionListener.Stub {
@@ -285,7 +285,7 @@
                             throw new IllegalArgumentException();
                         }
                         try {
-                            session.onGetSuggestionsMultipleForSentence(
+                            session.onGetSentenceSuggestionsMultiple(
                                     scp.mTextInfos, scp.mSuggestionsLimit);
                         } catch (RemoteException e) {
                             Log.e(TAG, "Failed to get suggestions " + e);
@@ -366,9 +366,9 @@
                             suggestionsLimit, sequentialWords));
         }
 
-        public void getSuggestionsMultipleForSentence(TextInfo[] textInfos, int suggestionsLimit) {
+        public void getSentenceSuggestionsMultiple(TextInfo[] textInfos, int suggestionsLimit) {
             if (DBG) {
-                Log.w(TAG, "getSuggestionsMultipleForSentence");
+                Log.w(TAG, "getSentenceSuggestionsMultiple");
             }
             processOrEnqueueTask(
                     new SpellCheckerParams(TASK_GET_SUGGESTIONS_MULTIPLE_FOR_SENTENCE,
@@ -399,8 +399,8 @@
                         while (!mPendingTasks.isEmpty()) {
                             final SpellCheckerParams tmp = mPendingTasks.poll();
                             if (tmp.mWhat == TASK_CLOSE) {
-                                // Only one close task should be processed, while we need to remove all
-                                // close tasks from the queue
+                                // Only one close task should be processed, while we need to remove
+                                // all close tasks from the queue
                                 closeTask = tmp;
                             }
                         }
@@ -426,7 +426,7 @@
         }
 
         @Override
-        public void onGetSuggestionsForSentence(SuggestionsInfo[] results) {
+        public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
             mHandler.sendMessage(
                     Message.obtain(mHandler, MSG_ON_GET_SUGGESTION_MULTIPLE_FOR_SENTENCE, results));
         }
@@ -444,7 +444,7 @@
         /**
          * @hide
          */
-        public void onGetSuggestionsForSentence(SuggestionsInfo[] results);
+        public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results);
     }
 
     private static class InternalListener extends ITextServicesSessionListener.Stub {
diff --git a/core/java/android/view/textservice/SuggestionsInfo.java b/core/java/android/view/textservice/SuggestionsInfo.java
index 9b99770..78bc1a9 100644
--- a/core/java/android/view/textservice/SuggestionsInfo.java
+++ b/core/java/android/view/textservice/SuggestionsInfo.java
@@ -21,14 +21,11 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import java.util.Arrays;
-
 /**
  * This class contains a metadata of suggestions from the text service
  */
 public final class SuggestionsInfo implements Parcelable {
     private static final String[] EMPTY = ArrayUtils.emptyArray(String.class);
-    private static final int NOT_A_LENGTH = -1;
 
     /**
      * Flag of the attributes of the suggestions that can be obtained by
@@ -50,8 +47,6 @@
     public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 0x0004;
     private final int mSuggestionsAttributes;
     private final String[] mSuggestions;
-    private final int[] mStartPosArray;
-    private final int[] mLengthArray;
     private final boolean mSuggestionsAvailable;
     private int mCookie;
     private int mSequence;
@@ -74,46 +69,12 @@
      */
     public SuggestionsInfo(
             int suggestionsAttributes, String[] suggestions, int cookie, int sequence) {
-        this(suggestionsAttributes, suggestions, cookie, sequence, null, null);
-    }
-
-    /**
-     * @hide
-     * Constructor.
-     * @param suggestionsAttributes from the text service
-     * @param suggestions from the text service
-     * @param cookie the cookie of the input TextInfo
-     * @param sequence the cookie of the input TextInfo
-     * @param startPosArray the array of start positions of suggestions
-     * @param lengthArray the array of length of suggestions
-     */
-    public SuggestionsInfo(
-            int suggestionsAttributes, String[] suggestions, int cookie, int sequence,
-            int[] startPosArray, int[] lengthArray) {
-        final int suggestsLen;
         if (suggestions == null) {
             mSuggestions = EMPTY;
             mSuggestionsAvailable = false;
-            suggestsLen = 0;
-            mStartPosArray = new int[0];
-            mLengthArray = new int[0];
         } else {
             mSuggestions = suggestions;
             mSuggestionsAvailable = true;
-            suggestsLen = suggestions.length;
-            if (startPosArray == null || lengthArray == null) {
-                mStartPosArray = new int[suggestsLen];
-                mLengthArray = new int[suggestsLen];
-                for (int i = 0; i < suggestsLen; ++i) {
-                    mStartPosArray[i] = 0;
-                    mLengthArray[i] = NOT_A_LENGTH;
-                }
-            } else if (suggestsLen != startPosArray.length || suggestsLen != lengthArray.length) {
-                throw new IllegalArgumentException();
-            } else {
-                mStartPosArray = Arrays.copyOf(startPosArray, suggestsLen);
-                mLengthArray = Arrays.copyOf(lengthArray, suggestsLen);
-            }
         }
         mSuggestionsAttributes = suggestionsAttributes;
         mCookie = cookie;
@@ -126,10 +87,6 @@
         mCookie = source.readInt();
         mSequence = source.readInt();
         mSuggestionsAvailable = source.readInt() == 1;
-        mStartPosArray = new int[mSuggestions.length];
-        mLengthArray = new int[mSuggestions.length];
-        source.readIntArray(mStartPosArray);
-        source.readIntArray(mLengthArray);
     }
 
     /**
@@ -145,8 +102,6 @@
         dest.writeInt(mCookie);
         dest.writeInt(mSequence);
         dest.writeInt(mSuggestionsAvailable ? 1 : 0);
-        dest.writeIntArray(mStartPosArray);
-        dest.writeIntArray(mLengthArray);
     }
 
     /**
@@ -227,24 +182,4 @@
     public int describeContents() {
         return 0;
     }
-
-    /**
-     * @hide
-     */
-    public int getSuggestionStartPosAt(int i) {
-        if (i >= 0 && i < mStartPosArray.length) {
-            return mStartPosArray[i];
-        }
-        return -1;
-    }
-
-    /**
-     * @hide
-     */
-    public int getSuggestionLengthAt(int i) {
-        if (i >= 0 && i < mLengthArray.length) {
-            return mLengthArray[i];
-        }
-        return -1;
-    }
 }
diff --git a/core/java/android/webkit/CacheManager.java b/core/java/android/webkit/CacheManager.java
index e21a02e..e2342e9 100644
--- a/core/java/android/webkit/CacheManager.java
+++ b/core/java/android/webkit/CacheManager.java
@@ -37,18 +37,18 @@
 import com.android.org.bouncycastle.crypto.digests.SHA1Digest;
 
 /**
- * The class CacheManager provides the persistent cache of content that is
- * received over the network. The component handles parsing of HTTP headers and
- * utilizes the relevant cache headers to determine if the content should be
- * stored and if so, how long it is valid for. Network requests are provided to
- * this component and if they can not be resolved by the cache, the HTTP headers
- * are attached, as appropriate, to the request for revalidation of content. The
- * class also manages the cache size.
- *
- * CacheManager may only be used if your activity contains a WebView.
- *
+ * Manages the HTTP cache used by an application's {@link WebView} instances.
  * @deprecated Access to the HTTP cache will be removed in a future release.
  */
+// The class CacheManager provides the persistent cache of content that is
+// received over the network. The component handles parsing of HTTP headers and
+// utilizes the relevant cache headers to determine if the content should be
+// stored and if so, how long it is valid for. Network requests are provided to
+// this component and if they can not be resolved by the cache, the HTTP headers
+// are attached, as appropriate, to the request for revalidation of content. The
+// class also manages the cache size.
+//
+// CacheManager may only be used if your activity contains a WebView.
 @Deprecated
 public final class CacheManager {
 
@@ -87,10 +87,9 @@
     private static boolean mClearCacheOnInit = false;
 
     /**
-     * This class represents a resource retrieved from the HTTP cache.
-     * Instances of this class can be obtained by invoking the
-     * CacheManager.getCacheFile() method.
-     *
+     * Represents a resource stored in the HTTP cache. Instances of this class
+     * can be obtained by calling
+     * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>))}.
      * @deprecated Access to the HTTP cache will be removed in a future release.
      */
     @Deprecated
@@ -114,64 +113,136 @@
         OutputStream outStream;
         File outFile;
 
+        /**
+         * Gets the status code of this cache entry.
+         * @return The status code of this cache entry
+         */
         public int getHttpStatusCode() {
             return httpStatusCode;
         }
 
+        /**
+         * Gets the content length of this cache entry.
+         * @return The content length of this cache entry
+         */
         public long getContentLength() {
             return contentLength;
         }
 
+        /**
+         * Gets the path of the file used to store the content of this cache
+         * entry, relative to the base directory of the cache. See
+         * {@link CacheManager#getCacheFileBaseDir CacheManager.getCacheFileBaseDir()}.
+         * @return The path of the file used to store this cache entry
+         */
         public String getLocalPath() {
             return localPath;
         }
 
+        /**
+         * Gets the expiry date of this cache entry, expressed in milliseconds
+         * since midnight, January 1, 1970 UTC.
+         * @return The expiry date of this cache entry
+         */
         public long getExpires() {
             return expires;
         }
 
+        /**
+         * Gets the expiry date of this cache entry, expressed as a string.
+         * @return The expiry date of this cache entry
+         *
+         */
         public String getExpiresString() {
             return expiresString;
         }
 
+        /**
+         * Gets the date at which this cache entry was last modified, expressed
+         * as a string.
+         * @return The date at which this cache entry was last modified
+         */
         public String getLastModified() {
             return lastModified;
         }
 
+        /**
+         * Gets the entity tag of this cache entry.
+         * @return The entity tag of this cache entry
+         */
         public String getETag() {
             return etag;
         }
 
+        /**
+         * Gets the MIME type of this cache entry.
+         * @return The MIME type of this cache entry
+         */
         public String getMimeType() {
             return mimeType;
         }
 
+        /**
+         * Gets the value of the HTTP 'Location' header with which this cache
+         * entry was received.
+         * @return The HTTP 'Location' header for this cache entry
+         */
         public String getLocation() {
             return location;
         }
 
+        /**
+         * Gets the encoding of this cache entry.
+         * @return The encoding of this cache entry
+         */
         public String getEncoding() {
             return encoding;
         }
 
+        /**
+         * Gets the value of the HTTP 'Content-Disposition' header with which
+         * this cache entry was received.
+         * @return The HTTP 'Content-Disposition' header for this cache entry
+         *
+         */
         public String getContentDisposition() {
             return contentdisposition;
         }
 
-        // For out-of-package access to the underlying streams.
+        /**
+         * Gets the input stream to the content of this cache entry, to allow
+         * content to be read. See
+         * {@link CacheManager#getCacheFile CacheManager.getCacheFile(String, Map<String, String>)}.
+         * @return An input stream to the content of this cache entry
+         */
         public InputStream getInputStream() {
             return inStream;
         }
 
+        /**
+         * Gets an output stream to the content of this cache entry, to allow
+         * content to be written. See
+         * {@link CacheManager#saveCacheFile CacheManager.saveCacheFile(String, CacheResult)}.
+         * @return An output stream to the content of this cache entry
+         */
+        // Note that this is always null for objects returned by getCacheFile()!
         public OutputStream getOutputStream() {
             return outStream;
         }
 
-        // These fields can be set manually.
+
+        /**
+         * Sets an input stream to the content of this cache entry.
+         * @param stream An input stream to the content of this cache entry
+         */
         public void setInputStream(InputStream stream) {
             this.inStream = stream;
         }
 
+        /**
+         * Sets the encoding of this cache entry.
+         * @param encoding The encoding of this cache entry
+         */
         public void setEncoding(String encoding) {
             this.encoding = encoding;
         }
@@ -185,11 +256,10 @@
     }
 
     /**
-     * Initialize the CacheManager.
-     *
-     * Note that this is called automatically when a {@link android.webkit.WebView} is created.
-     *
-     * @param context The application context.
+     * Initializes the HTTP cache. This method must be called before any
+     * CacheManager methods are used. Note that this is called automatically
+     * when a {@link WebView} is created.
+     * @param context The application context
      */
     static void init(Context context) {
         if (JniUtil.useChromiumHttpStack()) {
@@ -240,15 +310,10 @@
     }
 
     /**
-     * Get the base directory of the cache. Together with the local path of the CacheResult,
-     * obtained from {@link android.webkit.CacheManager.CacheResult#getLocalPath}, this
-     * identifies the cache file.
-     *
-     * Cache files are not guaranteed to be in this directory before
-     * CacheManager#getCacheFile(String, Map<String, String>) is called.
-     *
-     * @return File The base directory of the cache.
-     *
+     * Gets the base directory in which the files used to store the contents of
+     * cache entries are placed. See
+     * {@link CacheManager.CacheResult#getLocalPath CacheManager.CacheResult.getLocalPath()}.
+     * @return The base directory of the cache
      * @deprecated Access to the HTTP cache will be removed in a future release.
      */
     @Deprecated
@@ -257,8 +322,7 @@
     }
 
     /**
-     * Sets whether the cache is disabled.
-     *
+     * Sets whether the HTTP cache should be disabled.
      * @param disabled Whether the cache should be disabled
      */
     static void setCacheDisabled(boolean disabled) {
@@ -274,10 +338,8 @@
     }
 
     /**
-     * Whether the cache is disabled.
-     *
-     * @return return Whether the cache is disabled
-     *
+     * Gets whether the HTTP cache is disabled.
+     * @return True if the HTTP cache is disabled
      * @deprecated Access to the HTTP cache will be removed in a future release.
      */
     @Deprecated
@@ -330,20 +392,23 @@
         return ret;
     }
 
-    // only called from WebCore Thread
-    // make sure to call startCacheTransaction/endCacheTransaction in pair
     /**
-     * @deprecated Always returns false.
+     * Starts a cache transaction. Returns true if this is the only running
+     * transaction. Otherwise, this transaction is nested inside currently
+     * running transactions and false is returned.
+     * @return True if this is the only running transaction
+     * @deprecated This method no longer has any effect and always returns false
      */
     @Deprecated
     public static boolean startCacheTransaction() {
         return false;
     }
 
-    // only called from WebCore Thread
-    // make sure to call startCacheTransaction/endCacheTransaction in pair
     /**
-     * @deprecated Always returns false.
+     * Ends the innermost cache transaction and returns whether this was the
+     * only running transaction.
+     * @return True if this was the only running transaction
+     * @deprecated This method no longer has any effect and always returns false
      */
     @Deprecated
     public static boolean endCacheTransaction() {
@@ -351,15 +416,15 @@
     }
 
     /**
-     * Given a URL, returns the corresponding CacheResult if it exists, or null otherwise.
-     *
-     * The input stream of the CacheEntry object is initialized and opened and should be closed by
-     * the caller when access to the underlying file is no longer required.
-     * If a non-zero value is provided for the headers map, and the cache entry needs validation,
-     * HEADER_KEY_IFNONEMATCH or HEADER_KEY_IFMODIFIEDSINCE will be set in headers.
-     *
-     * @return The CacheResult for the given URL
-     *
+     * Gets the cache entry for the specified URL, or null if none is found.
+     * If a non-null value is provided for the HTTP headers map, and the cache
+     * entry needs validation, appropriate headers will be added to the map.
+     * The input stream of the CacheEntry object should be closed by the caller
+     * when access to the underlying file is no longer required.
+     * @param url The URL for which a cache entry is requested
+     * @param headers A map from HTTP header name to value, to be populated
+     *                for the returned cache entry
+     * @return The cache entry for the specified URL
      * @deprecated Access to the HTTP cache will be removed in a future release.
      */
     @Deprecated
@@ -368,32 +433,32 @@
         return getCacheFile(url, 0, headers);
     }
 
-    static CacheResult getCacheFile(String url, long postIdentifier,
-            Map<String, String> headers) {
-        if (mDisabled) {
+    private static CacheResult getCacheFileChromiumHttpStack(String url) {
+        assert JniUtil.useChromiumHttpStack();
+
+        CacheResult result = nativeGetCacheResult(url);
+        if (result == null) {
             return null;
         }
-
-        if (JniUtil.useChromiumHttpStack()) {
-            CacheResult result = nativeGetCacheResult(url);
-            if (result == null) {
-                return null;
-            }
-            // A temporary local file will have been created native side and localPath set
-            // appropriately.
-            File src = new File(mBaseDir, result.localPath);
-            try {
-                // Open the file here so that even if it is deleted, the content
-                // is still readable by the caller until close() is called.
-                result.inStream = new FileInputStream(src);
-            } catch (FileNotFoundException e) {
-                Log.v(LOGTAG, "getCacheFile(): Failed to open file: " + e);
-                // TODO: The files in the cache directory can be removed by the
-                // system. If it is gone, what should we do?
-                return null;
-            }
-            return result;
+        // A temporary local file will have been created native side and localPath set
+        // appropriately.
+        File src = new File(mBaseDir, result.localPath);
+        try {
+            // Open the file here so that even if it is deleted, the content
+            // is still readable by the caller until close() is called.
+            result.inStream = new FileInputStream(src);
+        } catch (FileNotFoundException e) {
+            Log.v(LOGTAG, "getCacheFile(): Failed to open file: " + e);
+            // TODO: The files in the cache directory can be removed by the
+            // system. If it is gone, what should we do?
+            return null;
         }
+        return result;
+    }
+
+    private static CacheResult getCacheFileAndroidHttpStack(String url,
+            long postIdentifier) {
+        assert !JniUtil.useChromiumHttpStack();
 
         String databaseKey = getDatabaseKey(url, postIdentifier);
         CacheResult result = mDataBase.getCache(databaseKey);
@@ -419,6 +484,22 @@
                 return null;
             }
         }
+        return result;
+    }
+
+    static CacheResult getCacheFile(String url, long postIdentifier,
+            Map<String, String> headers) {
+        if (mDisabled) {
+            return null;
+        }
+
+        CacheResult result = JniUtil.useChromiumHttpStack() ?
+                getCacheFileChromiumHttpStack(url) :
+                getCacheFileAndroidHttpStack(url, postIdentifier);
+
+        if (result == null) {
+            return null;
+        }
 
         // A null value for headers is used by CACHE_MODE_CACHE_ONLY to imply
         // that we should provide the cache result even if it is expired.
@@ -454,13 +535,8 @@
      * CacheResult, and is used to supply surrogate responses for URL
      * interception.
      * @return CacheResult for a given url
-     * @hide - hide createCacheFile since it has a parameter of type headers, which is
-     * in a hidden package.
-     *
-     * @deprecated Access to the HTTP cache will be removed in a future release.
      */
-    @Deprecated
-    public static CacheResult createCacheFile(String url, int statusCode,
+    static CacheResult createCacheFile(String url, int statusCode,
             Headers headers, String mimeType, boolean forceCache) {
         if (JniUtil.useChromiumHttpStack()) {
             // This method is public but hidden. We break functionality.
@@ -529,14 +605,15 @@
     }
 
     /**
-     * Save the info of a cache file for a given url to the CacheMap so that it
-     * can be reused later
-     *
+     * Adds a cache entry to the HTTP cache for the specicifed URL. Also closes
+     * the cache entry's output stream.
+     * @param url The URL for which the cache entry should be added
+     * @param cacheResult The cache entry to add
      * @deprecated Access to the HTTP cache will be removed in a future release.
      */
     @Deprecated
-    public static void saveCacheFile(String url, CacheResult cacheRet) {
-        saveCacheFile(url, 0, cacheRet);
+    public static void saveCacheFile(String url, CacheResult cacheResult) {
+        saveCacheFile(url, 0, cacheResult);
     }
 
     static void saveCacheFile(String url, long postIdentifier,
@@ -548,16 +625,26 @@
         }
 
         if (JniUtil.useChromiumHttpStack()) {
-            // This method is exposed in the public API but the API provides no way to obtain a
-            // new CacheResult object with a non-null output stream ...
-            // - CacheResult objects returned by getCacheFile() have a null output stream.
-            // - new CacheResult objects have a null output stream and no setter is provided.
-            // Since for the Android HTTP stack this method throws a null pointer exception in this
-            // case, this method is effectively useless from the point of view of the public API.
-
-            // We should already have thrown an exception above, to maintain 'backward
-            // compatibility' with the Android HTTP stack.
+            // This method is exposed in the public API but the API provides no
+            // way to obtain a new CacheResult object with a non-null output
+            // stream ...
+            // - CacheResult objects returned by getCacheFile() have a null
+            //   output stream.
+            // - new CacheResult objects have a null output stream and no
+            //   setter is provided.
+            // Since this method throws a null pointer exception in this case,
+            // it is effectively useless from the point of view of the public
+            // API.
+            //
+            // With the Chromium HTTP stack we continue to throw the same
+            // exception for 'backwards compatibility' with the Android HTTP
+            // stack.
+            //
+            // This method is not used from within this package with the
+            // Chromium HTTP stack, and for public API use, we should already
+            // have thrown an exception above.
             assert false;
+            return;
         }
 
         if (!cacheRet.outFile.exists()) {
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java
index 75ee338..95d9275 100644
--- a/core/java/android/webkit/CallbackProxy.java
+++ b/core/java/android/webkit/CallbackProxy.java
@@ -920,7 +920,10 @@
         if (PERF_PROBE) {
             mWebCoreThreadTime = SystemClock.currentThreadTimeMillis();
             mWebCoreIdleTime = 0;
-            Network.getInstance(mContext).startTiming();
+            if (!JniUtil.useChromiumHttpStack()) {
+                // Network is only used with the Android HTTP stack.
+                Network.getInstance(mContext).startTiming();
+            }
             // un-comment this if PERF_PROBE is true
 //            Looper.myQueue().setWaitCallback(mIdleCallback);
         }
@@ -938,7 +941,10 @@
             Log.d("WebCore", "WebCore thread used " +
                     (SystemClock.currentThreadTimeMillis() - mWebCoreThreadTime)
                     + " ms and idled " + mWebCoreIdleTime + " ms");
-            Network.getInstance(mContext).stopTiming();
+            if (!JniUtil.useChromiumHttpStack()) {
+                // Network is only used with the Android HTTP stack.
+                Network.getInstance(mContext).stopTiming();
+            }
         }
         Message msg = obtainMessage(PAGE_FINISHED, url);
         sendMessage(msg);
diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java
index 9fa5593..c500a76 100644
--- a/core/java/android/webkit/CookieManager.java
+++ b/core/java/android/webkit/CookieManager.java
@@ -34,7 +34,8 @@
 import java.util.TreeSet;
 
 /**
- * CookieManager manages cookies according to RFC2109 spec.
+ * Manages the cookies used by an application's {@link WebView} instances.
+ * Cookies are manipulated according to RFC2109.
  */
 public final class CookieManager {
 
@@ -99,7 +100,7 @@
 
     private boolean mAcceptCookie = true;
 
-    private int pendingCookieOperations = 0;
+    private int mPendingCookieOperations = 0;
 
     /**
      * This contains a list of 2nd-level domains that aren't allowed to have
@@ -246,12 +247,12 @@
     }
 
     /**
-     * Get a singleton CookieManager. If this is called before any
-     * {@link WebView} is created or outside of {@link WebView} context, the
-     * caller needs to call {@link CookieSyncManager#createInstance(Context)}
+     * Gets the singleton CookieManager instance. If this method is used
+     * before the application instantiates a {@link WebView} instance,
+     * {@link CookieSyncManager#createInstance(Context)} must be called
      * first.
      * 
-     * @return CookieManager
+     * @return The singleton CookieManager instance
      */
     public static synchronized CookieManager getInstance() {
         if (sRef == null) {
@@ -261,8 +262,10 @@
     }
 
     /**
-     * Control whether cookie is enabled or disabled
-     * @param accept TRUE if accept cookie
+     * Sets whether the application's {@link WebView} instances should send and
+     * accept cookies.
+     * @param accept Whether {@link WebView} instances should send and accept
+     *               cookies
      */
     public synchronized void setAcceptCookie(boolean accept) {
         if (JniUtil.useChromiumHttpStack()) {
@@ -274,8 +277,9 @@
     }
 
     /**
-     * Return whether cookie is enabled
-     * @return TRUE if accept cookie
+     * Gets whether the application's {@link WebView} instances send and accept
+     * cookies.
+     * @return True if {@link WebView} instances send and accept cookies
      */
     public synchronized boolean acceptCookie() {
         if (JniUtil.useChromiumHttpStack()) {
@@ -286,11 +290,13 @@
     }
 
     /**
-     * Set cookie for a given url. The old cookie with same host/path/name will
-     * be removed. The new cookie will be added if it is not expired or it does
-     * not have expiration which implies it is session cookie.
-     * @param url The url which cookie is set for
-     * @param value The value for set-cookie: in http response header
+     * Sets a cookie for the given URL. Any existing cookie with the same host,
+     * path and name will be replaced with the new cookie. The cookie being set
+     * must not have expired and must not be a session cookie, otherwise it
+     * will be ignored.
+     * @param url The URL for which the cookie is set
+     * @param value The cookie as a string, using the format of the
+     *              'Set-Cookie' HTTP response header
      */
     public void setCookie(String url, String value) {
         if (JniUtil.useChromiumHttpStack()) {
@@ -310,15 +316,13 @@
     }
 
     /**
-     * Set cookie for a given url. The old cookie with same host/path/name will
-     * be removed. The new cookie will be added if it is not expired or it does
-     * not have expiration which implies it is session cookie.
-     * @param url The url which cookie is set for
-     * @param value The value for set-cookie: in http response header
-     * @param privateBrowsing cookie jar to use
-     * @hide hiding private browsing
+     * See {@link setCookie(String, String)}
+     * @param url The URL for which the cookie is set
+     * @param value The value of the cookie, as a string, using the format of
+     *              the 'Set-Cookie' HTTP response header
+     * @param privateBrowsing Whether to use the private browsing cookie jar
      */
-    public void setCookie(String url, String value, boolean privateBrowsing) {
+    void setCookie(String url, String value, boolean privateBrowsing) {
         if (!JniUtil.useChromiumHttpStack()) {
             setCookie(url, value);
             return;
@@ -336,15 +340,12 @@
     }
 
     /**
-     * Set cookie for a given uri. The old cookie with same host/path/name will
-     * be removed. The new cookie will be added if it is not expired or it does
-     * not have expiration which implies it is session cookie.
-     * @param uri The uri which cookie is set for
-     * @param value The value for set-cookie: in http response header
-     * @hide - hide this because it takes in a parameter of type WebAddress,
-     * a system private class.
+     * See {@link setCookie(String, String)}
+     * @param uri The WebAddress for which the cookie is set
+     * @param value The value of the cookie, as a string, using the format of
+     *              the 'Set-Cookie' HTTP response header
      */
-    public synchronized void setCookie(WebAddress uri, String value) {
+    synchronized void setCookie(WebAddress uri, String value) {
         if (JniUtil.useChromiumHttpStack()) {
             nativeSetCookie(uri.toString(), value, false);
             return;
@@ -450,10 +451,10 @@
     }
 
     /**
-     * Get cookie(s) for a given url so that it can be set to "cookie:" in http
-     * request header.
-     * @param url The url needs cookie
-     * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
+     * Gets the cookies for the given URL.
+     * @param url The URL for which the cookies are requested
+     * @return value The cookies as a string, using the format of the 'Cookie'
+     *               HTTP request header
      */
     public String getCookie(String url) {
         if (JniUtil.useChromiumHttpStack()) {
@@ -472,12 +473,12 @@
     }
 
     /**
-     * Get cookie(s) for a given url so that it can be set to "cookie:" in http
-     * request header.
-     * @param url The url needs cookie
-     * @param privateBrowsing cookie jar to use
-     * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
-     * @hide Private mode is not very well exposed for now
+     * See {@link getCookie(String)}
+     * @param url The URL for which the cookies are requested
+     * @param privateBrowsing Whether to use the private browsing cookie jar
+     * @return value The cookies as a string, using the format of the 'Cookie'
+     *               HTTP request header
+     * @hide Used by Browser, no intention to publish.
      */
     public String getCookie(String url, boolean privateBrowsing) {
         if (!JniUtil.useChromiumHttpStack()) {
@@ -499,10 +500,10 @@
     /**
      * Get cookie(s) for a given uri so that it can be set to "cookie:" in http
      * request header.
-     * @param uri The uri needs cookie
-     * @return The cookies in the format of NAME=VALUE [; NAME=VALUE]
-     * @hide - hide this because it has a parameter of type WebAddress, which
-     * is a system private class.
+     * @param uri The WebAddress for which the cookies are requested
+     * @return value The cookies as a string, using the format of the 'Cookie'
+     *               HTTP request header
+     * @hide Used by RequestHandle, no intention to publish.
      */
     public synchronized String getCookie(WebAddress uri) {
         if (JniUtil.useChromiumHttpStack()) {
@@ -579,13 +580,12 @@
 
     /**
      * Waits for pending operations to completed.
-     * {@hide}  Too late to release publically.
      */
-    public void waitForCookieOperationsToComplete() {
+    void waitForCookieOperationsToComplete() {
         // Note that this function is applicable for both the java
         // and native http stacks, and works correctly with either.
         synchronized (this) {
-            while (pendingCookieOperations > 0) {
+            while (mPendingCookieOperations > 0) {
                 try {
                     wait();
                 } catch (InterruptedException e) { }
@@ -594,17 +594,18 @@
     }
 
     private synchronized void signalCookieOperationsComplete() {
-        pendingCookieOperations--;
-        assert pendingCookieOperations > -1;
+        mPendingCookieOperations--;
+        assert mPendingCookieOperations > -1;
         notify();
     }
 
     private synchronized void signalCookieOperationsStart() {
-        pendingCookieOperations++;
+        mPendingCookieOperations++;
     }
 
     /**
-     * Remove all session cookies, which are cookies without expiration date
+     * Removes all session cookies, which are cookies without an expiration
+     * date.
      */
     public void removeSessionCookie() {
         signalCookieOperationsStart();
@@ -643,7 +644,7 @@
     }
 
     /**
-     * Remove all cookies
+     * Removes all cookies.
      */
     public void removeAllCookie() {
         if (JniUtil.useChromiumHttpStack()) {
@@ -664,7 +665,8 @@
     }
 
     /**
-     *  Return true if there are stored cookies.
+     * Gets whether there are stored cookies.
+     * @return True if there are stored cookies.
      */
     public synchronized boolean hasCookies() {
         if (JniUtil.useChromiumHttpStack()) {
@@ -675,9 +677,9 @@
     }
 
     /**
-     *  Return true if there are stored cookies.
-     *  @param privateBrowsing cookie jar to use
-     *  @hide Hiding private mode
+     * See {@link hasCookies()}.
+     * @param privateBrowsing Whether to use the private browsing cookie jar
+     * @hide Used by Browser, no intention to publish.
      */
     public synchronized boolean hasCookies(boolean privateBrowsing) {
         if (!JniUtil.useChromiumHttpStack()) {
@@ -688,7 +690,7 @@
     }
 
     /**
-     * Remove all expired cookies
+     * Removes all expired cookies.
      */
     public void removeExpiredCookie() {
         if (JniUtil.useChromiumHttpStack()) {
@@ -733,7 +735,10 @@
     }
 
     /**
-     * Whether cookies are accepted for file scheme URLs.
+     * Gets whether the application's {@link WebView} instances send and accept
+     * cookies for file scheme URLs.
+     * @return True if {@link WebView} instances send and accept cookies for
+     *         file scheme URLs
      */
     public static boolean allowFileSchemeCookies() {
         if (JniUtil.useChromiumHttpStack()) {
@@ -744,13 +749,14 @@
     }
 
     /**
-     * Sets whether cookies are accepted for file scheme URLs.
-     *
-     * Use of cookies with file scheme URLs is potentially insecure. Do not use this feature unless
-     * you can be sure that no unintentional sharing of cookie data can take place.
+     * Sets whether the application's {@link WebView} instances should send and
+     * accept cookies for file scheme URLs.
+     * Use of cookies with file scheme URLs is potentially insecure. Do not use
+     * this feature unless you can be sure that no unintentional sharing of
+     * cookie data can take place.
      * <p>
-     * Note that calls to this method will have no effect if made after a WebView or CookieManager
-     * instance has been created.
+     * Note that calls to this method will have no effect if made after a
+     * {@link WebView} or CookieManager instance has been created.
      */
     public static void setAcceptFileSchemeCookies(boolean accept) {
         if (JniUtil.useChromiumHttpStack()) {
diff --git a/core/java/android/webkit/FindActionModeCallback.java b/core/java/android/webkit/FindActionModeCallback.java
index fffa90b..10b0885 100644
--- a/core/java/android/webkit/FindActionModeCallback.java
+++ b/core/java/android/webkit/FindActionModeCallback.java
@@ -43,7 +43,9 @@
     private Resources mResources;
     private boolean mMatchesFound;
     private int mNumberOfMatches;
+    private int mActiveMatchIndex;
     private ActionMode mActionMode;
+    private String mLastFind;
 
     FindActionModeCallback(Context context) {
         mCustomView = LayoutInflater.from(context).inflate(
@@ -132,16 +134,13 @@
             mWebView.clearMatches();
             mMatches.setVisibility(View.GONE);
             mMatchesFound = false;
+            mLastFind = null;
         } else {
             mMatchesFound = true;
-            mMatches.setVisibility(View.VISIBLE);
-            mNumberOfMatches = mWebView.findAll(find.toString());
-            if (0 == mNumberOfMatches) {
-                mMatches.setText(mResources.getString(
-                        com.android.internal.R.string.no_matches));
-            } else {
-                updateMatchesString();
-            }
+            mMatches.setVisibility(View.INVISIBLE);
+            mNumberOfMatches = 0;
+            mLastFind = find.toString();
+            mWebView.findAllAsync(mLastFind);
         }
     }
 
@@ -151,17 +150,31 @@
         mInput.showSoftInput(mEditText, 0);
     }
 
+    public void updateMatchCount(int matchIndex, int matchCount,
+        String findText) {
+        if (mLastFind != null && mLastFind.equals(findText)) {
+            mNumberOfMatches = matchCount;
+            mActiveMatchIndex = matchIndex;
+            updateMatchesString();
+        } else {
+            mMatches.setVisibility(View.INVISIBLE);
+            mNumberOfMatches = 0;
+        }
+    }
+
     /*
      * Update the string which tells the user how many matches were found, and
      * which match is currently highlighted.
-     * Not to be called when mNumberOfMatches is 0.
      */
     private void updateMatchesString() {
-        String template = mResources.getQuantityString(
+        if (mNumberOfMatches == 0) {
+            mMatches.setText(com.android.internal.R.string.no_matches);
+        } else {
+            mMatches.setText(mResources.getQuantityString(
                 com.android.internal.R.plurals.matches_found, mNumberOfMatches,
-                mWebView.findIndex() + 1, mNumberOfMatches);
-
-        mMatches.setText(template);
+                mActiveMatchIndex + 1, mNumberOfMatches));
+        }
+        mMatches.setVisibility(View.VISIBLE);
     }
 
     // OnLongClickListener implementation
diff --git a/core/java/android/webkit/LoadListener.java b/core/java/android/webkit/LoadListener.java
index 37e8bc0..4d7ade51 100644
--- a/core/java/android/webkit/LoadListener.java
+++ b/core/java/android/webkit/LoadListener.java
@@ -985,7 +985,7 @@
      * be used. This is just for forward/back navigation to a POST
      * URL.
      */
-    static boolean willLoadFromCache(String url, long identifier) {
+    private static boolean willLoadFromCache(String url, long identifier) {
         assert !JniUtil.useChromiumHttpStack();
         boolean inCache =
                 CacheManager.getCacheFile(url, identifier, null) != null;
diff --git a/core/java/android/webkit/WebResourceResponse.java b/core/java/android/webkit/WebResourceResponse.java
index e786838..24e0d11 100644
--- a/core/java/android/webkit/WebResourceResponse.java
+++ b/core/java/android/webkit/WebResourceResponse.java
@@ -21,9 +21,9 @@
 import java.io.InputStream;
 
 /**
- * A WebResourceResponse is return by
- * {@link WebViewClient#shouldInterceptRequest} and
- * contains the response information for a particular resource.
+ * Encapsulates a resource response. Applications can return an instance of this
+ * class from {@link WebViewClient#shouldInterceptRequest} to provide a custom
+ * response when the WebView requests a particular resource.
  */
 public class WebResourceResponse {
 
@@ -50,11 +50,13 @@
     private InputStream mInputStream;
 
     /**
-     * Construct a response with the given mime type, encoding, and data.
-     * @param mimeType The mime type of the data (i.e. text/html).
-     * @param encoding The encoding of the bytes read from data.
-     * @param data An InputStream for reading custom data.  The implementation
-     *             must implement {@link InputStream#read(byte[])}.
+     * Constructs a resource response with the given MIME type, encoding, and
+     * input stream. Callers must implement
+     * {@link InputStream#read(byte[]) InputStream.read(byte[])} for the input
+     * stream.
+     * @param mimeType The resource response's MIME type, for example text/html
+     * @param encoding The resource response's encoding
+     * @param data The input stream that provides the resource response's data
      */
     public WebResourceResponse(String mimeType, String encoding,
             InputStream data) {
@@ -64,47 +66,50 @@
     }
 
     /**
-     * Set the mime type of the response data (i.e. text/html).
-     * @param mimeType
+     * Sets the resource response's MIME type, for example text/html.
+     * @param mimeType The resource response's MIME type
      */
     public void setMimeType(String mimeType) {
         mMimeType = mimeType;
     }
 
     /**
-     * @see #setMimeType
+     * Gets the resource response's MIME type.
+     * @return The resource response's MIME type
      */
     public String getMimeType() {
         return mMimeType;
     }
 
     /**
-     * Set the encoding of the response data (i.e. utf-8).  This will be used to
-     * decode the raw bytes from the input stream.
-     * @param encoding
+     * Sets the resource response's encoding, for example UTF-8. This is used
+     * to decode the data from the input stream.
+     * @param encoding The resource response's encoding
      */
     public void setEncoding(String encoding) {
         mEncoding = encoding;
     }
 
     /**
-     * @see #setEncoding
+     * Gets the resource response's encoding.
+     * @return The resource response's encoding
      */
     public String getEncoding() {
         return mEncoding;
     }
 
     /**
-     * Set the input stream containing the data for this resource.
-     * @param data An InputStream for reading custom data.  The implementation
-     *             must implement {@link InputStream#read(byte[])}.
+     * Sets the input stream that provides the resource respone's data. Callers
+     * must implement {@link InputStream#read(byte[]) InputStream.read(byte[])}.
+     * @param data The input stream that provides the resource response's data
      */
     public void setData(InputStream data) {
         mInputStream = data;
     }
 
     /**
-     * @see #setData
+     * Gets the input stream that provides the resource respone's data.
+     * @return The input stream that provides the resource response's data
      */
     public InputStream getData() {
         return mInputStream;
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 9cd51d0..79bd35b 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.animation.ObjectAnimator;
 import android.annotation.Widget;
 import android.app.ActivityManager;
 import android.app.AlertDialog;
@@ -36,6 +37,7 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.ColorFilter;
 import android.graphics.DrawFilter;
 import android.graphics.Paint;
 import android.graphics.PaintFlagsDrawFilter;
@@ -59,6 +61,7 @@
 import android.os.StrictMode;
 import android.os.SystemClock;
 import android.provider.Settings;
+import android.security.KeyChain;
 import android.speech.tts.TextToSpeech;
 import android.text.Editable;
 import android.text.InputType;
@@ -913,7 +916,7 @@
     static final int REPLACE_BASE_CONTENT               = 123;
     static final int FORM_DID_BLUR                      = 124;
     static final int RETURN_LABEL                       = 125;
-    static final int FIND_AGAIN                         = 126;
+    static final int UPDATE_MATCH_COUNT                 = 126;
     static final int CENTER_FIT_RECT                    = 127;
     static final int REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID = 128;
     static final int SET_SCROLLBAR_MODES                = 129;
@@ -978,7 +981,7 @@
         "REPLACE_BASE_CONTENT", //           = 123;
         "FORM_DID_BLUR", //                  = 124;
         "RETURN_LABEL", //                   = 125;
-        "FIND_AGAIN", //                     = 126;
+        "UPDATE_MATCH_COUNT", //             = 126;
         "CENTER_FIT_RECT", //                = 127;
         "REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID", // = 128;
         "SET_SCROLLBAR_MODES", //            = 129;
@@ -1020,9 +1023,8 @@
 
     // keep these in sync with their counterparts in WebView.cpp
     private static final int DRAW_EXTRAS_NONE = 0;
-    private static final int DRAW_EXTRAS_FIND = 1;
-    private static final int DRAW_EXTRAS_SELECTION = 2;
-    private static final int DRAW_EXTRAS_CURSOR_RING = 3;
+    private static final int DRAW_EXTRAS_SELECTION = 1;
+    private static final int DRAW_EXTRAS_CURSOR_RING = 2;
 
     // keep this in sync with WebCore:ScrollbarMode in WebKit
     private static final int SCROLLBAR_AUTO = 0;
@@ -1303,6 +1305,7 @@
         init();
         setupPackageListener(context);
         setupProxyListener(context);
+        setupTrustStorageListener(context);
         updateMultiTouchSupport(context);
 
         if (privateBrowsing) {
@@ -1312,6 +1315,41 @@
         mAutoFillData = new WebViewCore.AutoFillData();
     }
 
+    private static class TrustStorageListener extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(KeyChain.ACTION_STORAGE_CHANGED)) {
+                handleCertTrustChanged();
+            }
+        }
+    }
+    private static TrustStorageListener sTrustStorageListener;
+
+    /**
+     * Handles update to the trust storage.
+     */
+    private static void handleCertTrustChanged() {
+        // send a message for indicating trust storage change
+        WebViewCore.sendStaticMessage(EventHub.TRUST_STORAGE_UPDATED, null);
+    }
+
+    /*
+     * @param context This method expects this to be a valid context.
+     */
+    private static void setupTrustStorageListener(Context context) {
+        if (sTrustStorageListener != null ) {
+            return;
+        }
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
+        sTrustStorageListener = new TrustStorageListener();
+        Intent current = 
+            context.getApplicationContext().registerReceiver(sTrustStorageListener, filter);
+        if (current != null) {
+            handleCertTrustChanged();
+        }
+    }
+
     private static class ProxyReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -1703,7 +1741,7 @@
     }
 
     /**
-     * returns the height of the titlebarview (if any). Does not care about
+     * Returns the height (in pixels) of the embedded title bar (if any). Does not care about
      * scrolling
      * @hide
      */
@@ -1712,12 +1750,15 @@
     }
 
     /**
-     * Return the amount of the titlebarview (if any) that is visible
+     * Return the visible height (in pixels) of the embedded title bar (if any).
      *
+     * @return This method is obsolete and always returns 0.
      * @deprecated This method is now obsolete.
      */
     @Deprecated
     public int getVisibleTitleHeight() {
+        // Actually, this method returns the height of the embedded title bar if one is set via the
+        // hidden setEmbeddedTitleBar method.
         checkThread();
         return getVisibleTitleHeightImpl();
     }
@@ -3671,7 +3712,7 @@
     public void findNext(boolean forward) {
         checkThread();
         if (0 == mNativeClass) return; // client isn't initialized
-        nativeFindNext(forward);
+        mWebViewCore.sendMessage(EventHub.FIND_NEXT, forward ? 1 : 0);
     }
 
     /*
@@ -3681,13 +3722,40 @@
      *              that were found.
      */
     public int findAll(String find) {
+        return findAllBody(find, false);
+    }
+
+    /**
+     * @hide
+     */
+    public void findAllAsync(String find) {
+        findAllBody(find, true);
+    }
+
+    private int findAllBody(String find, boolean isAsync) {
         checkThread();
         if (0 == mNativeClass) return 0; // client isn't initialized
-        int result = find != null ? nativeFindAll(find.toLowerCase(),
-                find.toUpperCase(), find.equalsIgnoreCase(mLastFind)) : 0;
-        invalidate();
         mLastFind = find;
-        return result;
+        mWebViewCore.removeMessages(EventHub.FIND_ALL);
+        WebViewCore.FindAllRequest request = new
+            WebViewCore.FindAllRequest(find);
+        if (isAsync) {
+            mWebViewCore.sendMessage(EventHub.FIND_ALL, request);
+            return 0; // no need to wait for response
+        }
+        synchronized(request) {
+            try {
+                mWebViewCore.sendMessageAtFrontOfQueue(EventHub.FIND_ALL,
+                    request);
+                while (request.mMatchCount == -1) {
+                    request.wait();
+                }
+            }
+            catch (InterruptedException e) {
+                return 0;
+            }
+        }
+        return request.mMatchCount;
     }
 
     /**
@@ -3723,6 +3791,7 @@
         }
         if (text != null) {
             mFindCallback.setText(text);
+            mFindCallback.findAll();
         }
         return true;
     }
@@ -3742,14 +3811,6 @@
         nativeSetFindIsUp(isUp);
     }
 
-    /**
-     * Return the index of the currently highlighted match.
-     */
-    int findIndex() {
-        if (0 == mNativeClass) return -1;
-        return nativeFindIndex();
-    }
-
     // Used to know whether the find dialog is open.  Affects whether
     // or not we draw the highlights for matches.
     private boolean mFindIsUp;
@@ -3816,10 +3877,11 @@
         checkThread();
         if (mNativeClass == 0)
             return;
-        nativeSetFindIsEmpty();
-        invalidate();
+        mWebViewCore.removeMessages(EventHub.FIND_ALL);
+        mWebViewCore.sendMessage(EventHub.FIND_ALL, null);
     }
 
+
     /**
      * Called when the find ActionMode ends.
      */
@@ -4561,15 +4623,7 @@
         if (mTitleBar != null) {
             canvas.translate(0, getTitleHeight());
         }
-        boolean drawJavaRings = !mTouchHighlightRegion.isEmpty()
-                && (mTouchMode == TOUCH_INIT_MODE
-                || mTouchMode == TOUCH_SHORTPRESS_START_MODE
-                || mTouchMode == TOUCH_SHORTPRESS_MODE
-                || mTouchMode == TOUCH_DONE_MODE);
-        boolean drawNativeRings = !drawJavaRings;
-        if (sDisableNavcache) {
-            drawNativeRings = !drawJavaRings && !isInTouchMode();
-        }
+        boolean drawNativeRings = !sDisableNavcache;
         drawContent(canvas, drawNativeRings);
         canvas.restoreToCount(saveCount);
 
@@ -4582,18 +4636,13 @@
             invalidate();
         }
 
-        // paint the highlight in the end
-        if (drawJavaRings) {
-            long delay = System.currentTimeMillis() - mTouchHighlightRequested;
-            if (delay < ViewConfiguration.getTapTimeout()) {
-                Rect r = mTouchHighlightRegion.getBounds();
-                postInvalidateDelayed(delay, r.left, r.top, r.right, r.bottom);
-            } else {
-                RegionIterator iter = new RegionIterator(mTouchHighlightRegion);
-                Rect r = new Rect();
-                while (iter.next(r)) {
-                    canvas.drawRect(r, mTouchHightlightPaint);
-                }
+        if (mFocusTransition != null) {
+            mFocusTransition.draw(canvas);
+        } else if (shouldDrawHighlightRect()) {
+            RegionIterator iter = new RegionIterator(mTouchHighlightRegion);
+            Rect r = new Rect();
+            while (iter.next(r)) {
+                canvas.drawRect(r, mTouchHightlightPaint);
             }
         }
         if (DEBUG_TOUCH_HIGHLIGHT) {
@@ -4914,12 +4963,12 @@
 
         // decide which adornments to draw
         int extras = DRAW_EXTRAS_NONE;
-        if (mFindIsUp) {
-            extras = DRAW_EXTRAS_FIND;
-        } else if (mSelectingText) {
-            extras = DRAW_EXTRAS_SELECTION;
-        } else if (drawCursorRing) {
-            extras = DRAW_EXTRAS_CURSOR_RING;
+        if (!mFindIsUp) {
+            if (mSelectingText) {
+                extras = DRAW_EXTRAS_SELECTION;
+            } else if (drawCursorRing) {
+                extras = DRAW_EXTRAS_CURSOR_RING;
+            }
         }
         if (DebugFlags.WEB_VIEW) {
             Log.v(LOGTAG, "mFindIsUp=" + mFindIsUp
@@ -8844,13 +8893,6 @@
                     }
                     break;
 
-                case FIND_AGAIN:
-                    // Ignore if find has been dismissed.
-                    if (mFindIsUp && mFindCallback != null) {
-                        mFindCallback.findAll();
-                    }
-                    break;
-
                 case DRAG_HELD_MOTIONLESS:
                     mHeldMotionless = MOTIONLESS_TRUE;
                     invalidate();
@@ -9055,6 +9097,14 @@
                     break;
                 }
 
+                case UPDATE_MATCH_COUNT: {
+                    if (mFindCallback != null) {
+                        mFindCallback.updateMatchCount(msg.arg1, msg.arg2,
+                            (String) msg.obj);
+                    }
+                    break;
+                }
+
                 default:
                     super.handleMessage(msg);
                     break;
@@ -9062,10 +9112,112 @@
         }
     }
 
+    private boolean shouldDrawHighlightRect() {
+        if (mFocusedNode == null || mInitialHitTestResult == null) {
+            return false;
+        }
+        if (mTouchHighlightRegion.isEmpty()) {
+            return false;
+        }
+        if (mFocusedNode.mHasFocus) {
+            return !mFocusedNode.mEditable;
+        }
+        if (mInitialHitTestResult.mType == HitTestResult.UNKNOWN_TYPE) {
+            return false;
+        }
+        long delay = System.currentTimeMillis() - mTouchHighlightRequested;
+        if (delay < ViewConfiguration.getTapTimeout()) {
+            Rect r = mTouchHighlightRegion.getBounds();
+            postInvalidateDelayed(delay, r.left, r.top, r.right, r.bottom);
+            return false;
+        }
+        return true;
+    }
+
+
+    private FocusTransitionDrawable mFocusTransition = null;
+    static class FocusTransitionDrawable extends Drawable {
+        Region mPreviousRegion;
+        Region mNewRegion;
+        float mProgress = 0;
+        WebView mWebView;
+        Paint mPaint;
+        int mMaxAlpha;
+        Point mTranslate;
+
+        public FocusTransitionDrawable(WebView view) {
+            mWebView = view;
+            mPaint = new Paint(mWebView.mTouchHightlightPaint);
+            mMaxAlpha = mPaint.getAlpha();
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter cf) {
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+        }
+
+        @Override
+        public int getOpacity() {
+            return 0;
+        }
+
+        public void setProgress(float p) {
+            mProgress = p;
+            if (mWebView.mFocusTransition == this) {
+                if (mProgress == 1f)
+                    mWebView.mFocusTransition = null;
+                mWebView.invalidate();
+            }
+        }
+
+        public float getProgress() {
+            return mProgress;
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            if (mTranslate == null) {
+                Rect bounds = mPreviousRegion.getBounds();
+                Point from = new Point(bounds.centerX(), bounds.centerY());
+                mNewRegion.getBounds(bounds);
+                Point to = new Point(bounds.centerX(), bounds.centerY());
+                mTranslate = new Point(from.x - to.x, from.y - to.y);
+            }
+            int alpha = (int) (mProgress * mMaxAlpha);
+            RegionIterator iter = new RegionIterator(mPreviousRegion);
+            Rect r = new Rect();
+            mPaint.setAlpha(mMaxAlpha - alpha);
+            float tx = mTranslate.x * mProgress;
+            float ty = mTranslate.y * mProgress;
+            int save = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+            canvas.translate(-tx, -ty);
+            while (iter.next(r)) {
+                canvas.drawRect(r, mPaint);
+            }
+            canvas.restoreToCount(save);
+            iter = new RegionIterator(mNewRegion);
+            r = new Rect();
+            mPaint.setAlpha(alpha);
+            save = canvas.save(Canvas.MATRIX_SAVE_FLAG);
+            tx = mTranslate.x - tx;
+            ty = mTranslate.y - ty;
+            canvas.translate(tx, ty);
+            while (iter.next(r)) {
+                canvas.drawRect(r, mPaint);
+            }
+            canvas.restoreToCount(save);
+        }
+    };
+
     private void setTouchHighlightRects(WebKitHitTest hit) {
+        FocusTransitionDrawable transition = new FocusTransitionDrawable(this);
         Rect[] rects = hit != null ? hit.mTouchRects : null;
         if (!mTouchHighlightRegion.isEmpty()) {
             invalidate(mTouchHighlightRegion.getBounds());
+            transition.mPreviousRegion = new Region(mTouchHighlightRegion);
             mTouchHighlightRegion.setEmpty();
         }
         if (rects != null) {
@@ -9084,7 +9236,13 @@
                             + viewRect);
                 }
             }
+            transition.mNewRegion = new Region(mTouchHighlightRegion);
             invalidate(mTouchHighlightRegion.getBounds());
+            if (hit.mHasFocus && transition.mPreviousRegion != null) {
+                mFocusTransition = transition;
+                ObjectAnimator animator = ObjectAnimator.ofFloat(mFocusTransition, "progress", 1f);
+                animator.start();
+            }
         }
     }
 
@@ -9891,9 +10049,6 @@
     private native void     nativeUpdateDrawGLFunction(Rect rect, Rect viewRect,
             RectF visibleRect, float scale);
     private native void     nativeExtendSelection(int x, int y);
-    private native int      nativeFindAll(String findLower, String findUpper,
-            boolean sameAsLastSearch);
-    private native void     nativeFindNext(boolean forward);
     /* package */ native int      nativeFocusCandidateFramePointer();
     /* package */ native boolean  nativeFocusCandidateHasNextTextfield();
     /* package */ native boolean  nativeFocusCandidateIsPassword();
@@ -9951,9 +10106,7 @@
     private native boolean  nativePointInNavCache(int x, int y, int slop);
     private native void     nativeSelectBestAt(Rect rect);
     private native void     nativeSelectAt(int x, int y);
-    private native int      nativeFindIndex();
     private native void     nativeSetExtendSelection();
-    private native void     nativeSetFindIsEmpty();
     private native void     nativeSetFindIsUp(boolean isUp);
     private native void     nativeSetHeightCanMeasure(boolean measure);
     private native boolean  nativeSetBaseLayer(int nativeInstance,
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 14ecfbd..ee27dd4 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -26,6 +26,7 @@
 import android.media.MediaFile;
 import android.net.ProxyProperties;
 import android.net.Uri;
+import android.net.http.CertificateChainValidator;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -775,6 +776,11 @@
                                 Message m = (Message)msg.obj;
                                 m.sendToTarget();
                                 break;
+                            case EventHub.TRUST_STORAGE_UPDATED:
+                                // post a task to network thread for updating trust manager
+                                nativeCertTrustChanged();
+                                CertificateChainValidator.handleTrustStorageUpdate();
+                                break;
                         }
                     }
                 };
@@ -881,6 +887,7 @@
         boolean mEditable;
         int mTapHighlightColor = WebView.HIGHLIGHT_COLOR;
         Rect[] mEnclosingParentRects;
+        boolean mHasFocus;
 
         // These are the input values that produced this hit test
         int mHitTestX;
@@ -995,6 +1002,15 @@
             "REMOVE_JS_INTERFACE", // = 149;
         };
 
+    static class FindAllRequest {
+        public FindAllRequest(String text) {
+            mSearchText = text;
+            mMatchCount = -1;
+        }
+        public String mSearchText;
+        public int mMatchCount;
+    }
+
     /**
      * @hide
      */
@@ -1133,6 +1149,13 @@
         static final int SELECT_WORD_AT = 214;
         static final int SELECT_ALL = 215;
 
+        // for updating state on trust storage change
+        static final int TRUST_STORAGE_UPDATED = 220;
+
+        // find-on-page controls
+        static final int FIND_ALL = 220;
+        static final int FIND_NEXT = 221;
+
         // Private handler for WebCore messages.
         private Handler mHandler;
         // Message queue for containing messages before the WebCore thread is
@@ -1776,6 +1799,22 @@
                         case SELECT_ALL:
                             nativeSelectAll(mNativeClass);
                             break;
+                        case FIND_ALL: {
+                            FindAllRequest request = (FindAllRequest) msg.obj;
+                            if (request == null) {
+                                nativeFindAll(mNativeClass, null);
+                            } else {
+                                request.mMatchCount = nativeFindAll(
+                                    mNativeClass, request.mSearchText);
+                                synchronized(request) {
+                                    request.notify();
+                                }
+                            }
+                            break;
+                        }
+                        case FIND_NEXT:
+                            nativeFindNext(mNativeClass, msg.arg1 != 0);
+                            break;
                     }
                 }
             };
@@ -2774,13 +2813,6 @@
     }
 
     // called by JNI
-    private void sendFindAgain() {
-        if (mWebView == null) return;
-        Message.obtain(mWebView.mPrivateHandler,
-                WebView.FIND_AGAIN).sendToTarget();
-    }
-
-    // called by JNI
     private void initEditField(int pointer, String text, int start, int end) {
         if (mWebView == null) {
             return;
@@ -2793,6 +2825,17 @@
                 .sendToTarget();
     }
 
+    // called by JNI
+    private void updateMatchCount(int matchIndex, int matchCount,
+        String findText) {
+        if (mWebView == null) {
+            return;
+        }
+        Message.obtain(mWebView.mPrivateHandler,
+                WebView.UPDATE_MATCH_COUNT, matchIndex, matchCount,
+                findText).sendToTarget();
+    }
+
     private native void nativeUpdateFrameCacheIfLoading(int nativeClass);
     private native void nativeRevealSelection(int nativeClass);
     private native String nativeRequestLabel(int nativeClass, int framePtr,
@@ -3046,6 +3089,8 @@
 
     private native void nativeAutoFillForm(int nativeClass, int queryId);
     private native void nativeScrollLayer(int nativeClass, int layer, Rect rect);
+    private native int nativeFindAll(int nativeClass, String text);
+    private native void nativeFindNext(int nativeClass, boolean forward);
 
     /**
      * Deletes editable text between two points. Note that the selection may
@@ -3082,4 +3127,6 @@
     private native void nativeClearTextSelection(int nativeClass);
     private native void nativeSelectWordAt(int nativeClass, int x, int y);
     private native void nativeSelectAll(int nativeClass);
+
+    private static native void nativeCertTrustChanged();
 }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index e94b1cb..e7bc1e1 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -36,6 +36,7 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.LongSparseArray;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
 import android.util.StateSet;
 import android.view.ActionMode;
@@ -87,6 +88,8 @@
         ViewTreeObserver.OnTouchModeChangeListener,
         RemoteViewsAdapter.RemoteAdapterConnectionCallback {
 
+    private static final String TAG = "AbsListView";
+
     /**
      * Disables the transcript mode.
      *
@@ -263,6 +266,11 @@
     private RemoteViewsAdapter mRemoteAdapter;
 
     /**
+     * If mAdapter != null, whenever this is true the adapter has stable IDs.
+     */
+    boolean mAdapterHasStableIds;
+
+    /**
      * This flag indicates the a full notify is required when the RemoteViewsAdapter connects
      */
     private boolean mDeferNotifyDataSetChanged = false;
@@ -812,7 +820,8 @@
     @Override
     public void setAdapter(ListAdapter adapter) {
         if (adapter != null) {
-            if (mChoiceMode != CHOICE_MODE_NONE && mAdapter.hasStableIds() &&
+            mAdapterHasStableIds = mAdapter.hasStableIds();
+            if (mChoiceMode != CHOICE_MODE_NONE && mAdapterHasStableIds &&
                     mCheckedIdStates == null) {
                 mCheckedIdStates = new LongSparseArray<Integer>();
             }
@@ -2011,6 +2020,11 @@
         isScrap[0] = false;
         View scrapView;
 
+        scrapView = mRecycler.getTransientStateView(position);
+        if (scrapView != null) {
+            return scrapView;
+        }
+
         scrapView = mRecycler.getScrapView(position);
 
         View child;
@@ -2021,6 +2035,13 @@
             }
 
             child = mAdapter.getView(position, scrapView, this);
+            if (mAdapterHasStableIds) {
+                LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp == null) {
+                    lp = (LayoutParams) generateDefaultLayoutParams();
+                }
+                lp.itemId = mAdapter.getItemId(position);
+            }
 
             if (ViewDebug.TRACE_RECYCLER) {
                 ViewDebug.trace(child, ViewDebug.RecyclerTraceType.BIND_VIEW,
@@ -4543,7 +4564,9 @@
 
         if (count > 0) {
             detachViewsFromParent(start, count);
+            mRecycler.removeSkippedScrap();
         }
+
         offsetChildrenTopAndBottom(incrementalDeltaY);
 
         if (down) {
@@ -4853,6 +4876,9 @@
             confirmCheckedPositionsById();
         }
 
+        // TODO: In the future we can recycle these views based on stable ID instead.
+        mRecycler.clearTransientStateViews();
+
         if (count > 0) {
             int newPos;
             int selectablePos;
@@ -5735,6 +5761,11 @@
          */
         int scrappedFromPosition;
 
+        /**
+         * The ID the view represents
+         */
+        long itemId = -1;
+
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
         }
@@ -5807,6 +5838,10 @@
 
         private ArrayList<View> mCurrentScrap;
 
+        private ArrayList<View> mSkippedScrap;
+
+        private SparseArray<View> mTransientStateViews;
+
         public void setViewTypeCount(int viewTypeCount) {
             if (viewTypeCount < 1) {
                 throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
@@ -5838,6 +5873,12 @@
                     }
                 }
             }
+            if (mTransientStateViews != null) {
+                final int count = mTransientStateViews.size();
+                for (int i = 0; i < count; i++) {
+                    mTransientStateViews.valueAt(i).forceLayout();
+                }
+            }
         }
 
         public boolean shouldRecycleViewType(int viewType) {
@@ -5864,6 +5905,9 @@
                     }
                 }
             }
+            if (mTransientStateViews != null) {
+                mTransientStateViews.clear();
+            }
         }
 
         /**
@@ -5910,6 +5954,28 @@
             return null;
         }
 
+        View getTransientStateView(int position) {
+            if (mTransientStateViews == null) {
+                return null;
+            }
+            final int index = mTransientStateViews.indexOfKey(position);
+            if (index < 0) {
+                return null;
+            }
+            final View result = mTransientStateViews.valueAt(index);
+            mTransientStateViews.removeAt(index);
+            return result;
+        }
+
+        /**
+         * Dump any currently saved views with transient state.
+         */
+        void clearTransientStateViews() {
+            if (mTransientStateViews != null) {
+                mTransientStateViews.clear();
+            }
+        }
+
         /**
          * @return A view from the ScrapViews collection. These are unordered.
          */
@@ -5926,7 +5992,7 @@
         }
 
         /**
-         * Put a view into the ScapViews list. These views are unordered.
+         * Put a view into the ScrapViews list. These views are unordered.
          *
          * @param scrap The view to add
          */
@@ -5936,23 +6002,32 @@
                 return;
             }
 
+            lp.scrappedFromPosition = position;
+
             // Don't put header or footer views or views that should be ignored
             // into the scrap heap
             int viewType = lp.viewType;
-            if (!shouldRecycleViewType(viewType)) {
-                if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
-                    removeDetachedView(scrap, false);
+            final boolean scrapHasTransientState = scrap.hasTransientState();
+            if (!shouldRecycleViewType(viewType) || scrapHasTransientState) {
+                if (viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER || scrapHasTransientState) {
+                    if (mSkippedScrap == null) {
+                        mSkippedScrap = new ArrayList<View>();
+                    }
+                    mSkippedScrap.add(scrap);
+                }
+                if (scrapHasTransientState) {
+                    if (mTransientStateViews == null) {
+                        mTransientStateViews = new SparseArray<View>();
+                    }
+                    mTransientStateViews.put(position, scrap);
                 }
                 return;
             }
 
-            lp.scrappedFromPosition = position;
-
+            scrap.dispatchStartTemporaryDetach();
             if (mViewTypeCount == 1) {
-                scrap.dispatchStartTemporaryDetach();
                 mCurrentScrap.add(scrap);
             } else {
-                scrap.dispatchStartTemporaryDetach();
                 mScrapViews[viewType].add(scrap);
             }
 
@@ -5962,6 +6037,20 @@
         }
 
         /**
+         * Finish the removal of any views that skipped the scrap heap.
+         */
+        void removeSkippedScrap() {
+            if (mSkippedScrap == null) {
+                return;
+            }
+            final int count = mSkippedScrap.size();
+            for (int i = 0; i < count; i++) {
+                removeDetachedView(mSkippedScrap.get(i), false);
+            }
+            mSkippedScrap.clear();
+        }
+
+        /**
          * Move all views remaining in mActiveViews to mScrapViews.
          */
         void scrapActiveViews() {
@@ -5980,11 +6069,19 @@
 
                     activeViews[i] = null;
 
-                    if (!shouldRecycleViewType(whichScrap)) {
+                    final boolean scrapHasTransientState = victim.hasTransientState();
+                    if (!shouldRecycleViewType(whichScrap) || scrapHasTransientState) {
                         // Do not move views that should be ignored
-                        if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
+                        if (whichScrap != ITEM_VIEW_TYPE_HEADER_OR_FOOTER ||
+                                scrapHasTransientState) {
                             removeDetachedView(victim, false);
                         }
+                        if (scrapHasTransientState) {
+                            if (mTransientStateViews == null) {
+                                mTransientStateViews = new SparseArray<View>();
+                            }
+                            mTransientStateViews.put(mFirstActivePosition + i, victim);
+                        }
                         continue;
                     }
 
diff --git a/core/java/android/widget/CheckedTextView.java b/core/java/android/widget/CheckedTextView.java
index 5c7e5a3..dd53325 100644
--- a/core/java/android/widget/CheckedTextView.java
+++ b/core/java/android/widget/CheckedTextView.java
@@ -142,12 +142,8 @@
         resolvePadding();
     }
 
-    /**
-     * @hide
-     */
     @Override
-    protected void resolvePadding() {
-        super.resolvePadding();
+    public void onResolvePadding(int layoutDirection) {
         int newPadding = (mCheckMarkDrawable != null) ?
                 mCheckMarkWidth + mBasePadding : mBasePadding;
         mNeedRequestlayout |= (mPaddingRight != newPadding);
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 326587e..83aa8ba 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -56,7 +56,7 @@
     // Time it will take in ms for a pulled glow to decay to partial strength before release
     private static final int PULL_DECAY_TIME = 1000;
 
-    private static final float MAX_ALPHA = 0.8f;
+    private static final float MAX_ALPHA = 1.f;
     private static final float HELD_EDGE_ALPHA = 0.7f;
     private static final float HELD_EDGE_SCALE_Y = 0.5f;
     private static final float HELD_GLOW_ALPHA = 0.5f;
diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java
index ea40dc2..fc08cc5 100644
--- a/core/java/android/widget/GridLayout.java
+++ b/core/java/android/widget/GridLayout.java
@@ -127,8 +127,7 @@
  *
  * GridLayout does not provide support for the principle of <em>weight</em>, as defined in
  * {@link LinearLayout.LayoutParams#weight}. In general, it is not therefore possible
- * to configure a GridLayout to distribute excess space in non-trivial proportions between
- * multiple rows or columns.
+ * to configure a GridLayout to distribute excess space between multiple components.
  * <p>
  * Some common use-cases may nevertheless be accommodated as follows.
  * To place equal amounts of space around a component in a cell group;
@@ -209,7 +208,6 @@
 
     static final String TAG = GridLayout.class.getName();
     static final boolean DEBUG = false;
-    static final int PRF = 1;
     static final int MAX_SIZE = 100000;
     static final int DEFAULT_CONTAINER_MARGIN = 0;
     static final int UNINITIALIZED_HASH = 0;
@@ -779,7 +777,7 @@
         }
     }
 
-    private void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
+    private static void drawRect(Canvas canvas, int x1, int y1, int x2, int y2, Paint paint) {
         canvas.drawRect(x1, y1, x2 - 1, y2 - 1, paint);
     }
 
@@ -957,10 +955,6 @@
                 resolveSizeAndState(measuredHeight, heightSpec, 0));
     }
 
-    private int protect(int alignment) {
-        return (alignment == UNDEFINED) ? 0 : alignment;
-    }
-
     private int getMeasurement(View c, boolean horizontal) {
         return horizontal ? c.getMeasuredWidth() : c.getMeasuredHeight();
     }
@@ -1040,42 +1034,31 @@
             Alignment hAlign = getAlignment(columnSpec.alignment, true);
             Alignment vAlign = getAlignment(rowSpec.alignment, false);
 
-            Bounds colBounds = horizontalAxis.getGroupBounds().getValue(i);
-            Bounds rowBounds = verticalAxis.getGroupBounds().getValue(i);
+            Bounds boundsX = horizontalAxis.getGroupBounds().getValue(i);
+            Bounds boundsY = verticalAxis.getGroupBounds().getValue(i);
 
             // Gravity offsets: the location of the alignment group relative to its cell group.
-            //noinspection NullableProblems
-            int gravityOffsetX = protect(hAlign.getAlignmentValue(null,
-                    cellWidth - colBounds.size(true)));
-            //noinspection NullableProblems
-            int gravityOffsetY = protect(vAlign.getAlignmentValue(null,
-                    cellHeight - rowBounds.size(true)));
+            int gravityOffsetX = hAlign.getGravityOffset(c, cellWidth - boundsX.size(true));
+            int gravityOffsetY = vAlign.getGravityOffset(c, cellHeight - boundsY.size(true));
 
-            boolean rtl = isLayoutRtl();
-            int startMargin = getMargin(c, true, !rtl);
+            int leftMargin = getMargin(c, true, true);
             int topMargin = getMargin(c, false, true);
-            int endMargin = getMargin(c, true, rtl);
+            int rightMargin = getMargin(c, true, false);
             int bottomMargin = getMargin(c, false, false);
 
-            // Same calculation as getMeasurementIncludingMargin()
-            int mWidth = startMargin + pWidth + endMargin;
-            int mHeight = topMargin + pHeight + bottomMargin;
-
             // Alignment offsets: the location of the view relative to its alignment group.
-            int alignmentOffsetX = colBounds.getOffset(c, hAlign, mWidth);
-            int alignmentOffsetY = rowBounds.getOffset(c, vAlign, mHeight);
+            int alignmentOffsetX = boundsX.getOffset(c, hAlign, leftMargin + pWidth + rightMargin);
+            int alignmentOffsetY = boundsY.getOffset(c, vAlign, topMargin + pHeight + bottomMargin);
 
-            int dx = gravityOffsetX + alignmentOffsetX + startMargin;
-            int dy = gravityOffsetY + alignmentOffsetY + topMargin;
+            int width = hAlign.getSizeInCell(c, pWidth, cellWidth - leftMargin - rightMargin);
+            int height = vAlign.getSizeInCell(c, pHeight, cellHeight - topMargin - bottomMargin);
 
-            cellWidth -= startMargin + endMargin;
-            cellHeight -= topMargin + bottomMargin;
+            int dx = x1 + gravityOffsetX + alignmentOffsetX;
 
-            int width = hAlign.getSizeInCell(c, pWidth, cellWidth, PRF);
-            int height = vAlign.getSizeInCell(c, pHeight, cellHeight, PRF);
+            int cx = !isLayoutRtl() ? paddingLeft + leftMargin + dx :
+                    targetWidth - width - paddingRight - rightMargin - dx;
+            int cy = paddingTop + y1 + gravityOffsetY + alignmentOffsetY + topMargin;
 
-            int cx = rtl ? targetWidth - paddingRight - x1 - dx - width : paddingLeft + x1 + dx;
-            int cy = paddingTop + y1 + dy;
             if (width != c.getMeasuredWidth() || height != c.getMeasuredHeight()) {
                 c.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
             }
@@ -1694,7 +1677,7 @@
      * each cell group. The fundamental parameters associated with each cell group are
      * gathered into their vertical and horizontal components and stored
      * in the {@link #rowSpec} and {@link #columnSpec} layout parameters.
-     * {@link android.widget.GridLayout.Spec Specs} are immutable structures
+     * {@link GridLayout.Spec Specs} are immutable structures
      * and may be shared between the layout parameters of different children.
      * <p>
      * The row and column specs contain the leading and trailing indices along each axis
@@ -1747,7 +1730,7 @@
      *     <li>{@link #rowSpec}<code>.alignment</code> = {@link #BASELINE} </li>
      *     <li>{@link #columnSpec}<code>.column</code> = {@link #UNDEFINED} </li>
      *     <li>{@link #columnSpec}<code>.columnSpan</code> = 1 </li>
-     *     <li>{@link #columnSpec}<code>.alignment</code> = {@link #LEFT} </li>
+     *     <li>{@link #columnSpec}<code>.alignment</code> = {@link #START} </li>
      * </ul>
      *
      * See {@link GridLayout} for a more complete description of the conventions
@@ -1936,7 +1919,7 @@
 
         /**
          * Describes how the child views are positioned. Default is {@code LEFT | BASELINE}.
-         * See {@link android.view.Gravity}.
+         * See {@link Gravity}.
          *
          * @param gravity the new gravity value
          *
@@ -2426,8 +2409,8 @@
      * group is specified by the two alignments which act along each axis independently.
      * <p>
      *  The GridLayout class defines the most common alignments used in general layout:
-     * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #CENTER}, {@link
-     * #BASELINE} and {@link #FILL}.
+     * {@link #TOP}, {@link #LEFT}, {@link #BOTTOM}, {@link #RIGHT}, {@link #START},
+     * {@link #END}, {@link #CENTER}, {@link #BASELINE} and {@link #FILL}.
      */
     /*
      * An Alignment implementation must define {@link #getAlignmentValue(View, int, int)},
@@ -2441,6 +2424,8 @@
         Alignment() {
         }
 
+        abstract int getGravityOffset(View view, int cellDelta);
+
         /**
          * Returns an alignment value. In the case of vertical alignments the value
          * returned should indicate the distance from the top of the view to the
@@ -2463,12 +2448,9 @@
          * @param view              the view to which this alignment should be applied
          * @param viewSize          the measured size of the view
          * @param cellSize          the size of the cell into which this view will be placed
-         * @param measurementType   This parameter is currently unused as GridLayout only supports
-         *                          one type of measurement: {@link View#measure(int, int)}.
-         *
          * @return the aligned size
          */
-        int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
+        int getSizeInCell(View view, int viewSize, int cellSize) {
             return viewSize;
         }
 
@@ -2479,6 +2461,11 @@
 
     static final Alignment UNDEFINED_ALIGNMENT = new Alignment() {
         @Override
+        int getGravityOffset(View view, int cellDelta) {
+            return UNDEFINED;
+        }
+
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return UNDEFINED;
         }
@@ -2490,6 +2477,11 @@
      */
     private static final Alignment LEADING = new Alignment() {
         @Override
+        int getGravityOffset(View view, int cellDelta) {
+            return 0;
+        }
+
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return 0;
         }
@@ -2501,6 +2493,11 @@
      */
     private static final Alignment TRAILING = new Alignment() {
         @Override
+        int getGravityOffset(View view, int cellDelta) {
+            return cellDelta;
+        }
+
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return viewSize;
         }
@@ -2530,15 +2527,16 @@
      */
     public static final Alignment END = TRAILING;
 
-    private static Alignment getAbsoluteAlignment(final Alignment a1, final Alignment a2) {
+    private static Alignment createSwitchingAlignment(final Alignment ltr, final Alignment rtl) {
         return new Alignment() {
             @Override
+            int getGravityOffset(View view, int cellDelta) {
+                return (!view.isLayoutRtl() ? ltr : rtl).getGravityOffset(view, cellDelta);
+            }
+
+            @Override
             public int getAlignmentValue(View view, int viewSize) {
-                if (view == null) {
-                    return UNDEFINED;
-                }
-                Alignment alignment = view.isLayoutRtl() ? a2 : a1;
-                return alignment.getAlignmentValue(view, viewSize);
+                return (!view.isLayoutRtl() ? ltr : rtl).getAlignmentValue(view, viewSize);
             }
         };
     }
@@ -2547,13 +2545,13 @@
      * Indicates that a view should be aligned with the <em>left</em>
      * edges of the other views in its cell group.
      */
-    public static final Alignment LEFT = getAbsoluteAlignment(START, END);
+    public static final Alignment LEFT = createSwitchingAlignment(START, END);
 
     /**
      * Indicates that a view should be aligned with the <em>right</em>
      * edges of the other views in its cell group.
      */
-    public static final Alignment RIGHT = getAbsoluteAlignment(END, START);
+    public static final Alignment RIGHT = createSwitchingAlignment(END, START);
 
     /**
      * Indicates that a view should be <em>centered</em> with the other views in its cell group.
@@ -2562,6 +2560,11 @@
      */
     public static final Alignment CENTER = new Alignment() {
         @Override
+        int getGravityOffset(View view, int cellDelta) {
+            return cellDelta >> 1;
+        }
+
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return viewSize >> 1;
         }
@@ -2576,10 +2579,12 @@
      */
     public static final Alignment BASELINE = new Alignment() {
         @Override
+        int getGravityOffset(View view, int cellDelta) {
+            return 0; // baseline gravity is top
+        }
+
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
-            if (view == null) {
-                return UNDEFINED;
-            }
             int baseline = view.getBaseline();
             return (baseline == -1) ? UNDEFINED : baseline;
         }
@@ -2627,12 +2632,17 @@
      */
     public static final Alignment FILL = new Alignment() {
         @Override
+        int getGravityOffset(View view, int cellDelta) {
+            return 0;
+        }
+
+        @Override
         public int getAlignmentValue(View view, int viewSize) {
             return UNDEFINED;
         }
 
         @Override
-        public int getSizeInCell(View view, int viewSize, int cellSize, int measurementType) {
+        public int getSizeInCell(View view, int viewSize, int cellSize) {
             return cellSize;
         }
     };
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index be2df8e..6bc5a15 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1205,6 +1205,7 @@
             // Clear out old views
             //removeAllViewsInLayout();
             detachAllViewsFromParent();
+            recycleBin.removeSkippedScrap();
 
             switch (mLayoutMode) {
             case LAYOUT_SET_SELECTION:
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 67fd059..46c2c07 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1591,6 +1591,7 @@
 
             // Clear out old views
             detachAllViewsFromParent();
+            recycleBin.removeSkippedScrap();
 
             switch (mLayoutMode) {
             case LAYOUT_SET_SELECTION:
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 909f383..a1cf205 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -24,6 +24,7 @@
 import android.text.method.WordIterator;
 import android.text.style.SpellCheckSpan;
 import android.text.style.SuggestionSpan;
+import android.view.textservice.SentenceSuggestionsInfo;
 import android.view.textservice.SpellCheckerSession;
 import android.view.textservice.SpellCheckerSession.SpellCheckerSessionListener;
 import android.view.textservice.SuggestionsInfo;
@@ -277,9 +278,9 @@
     }
 
     @Override
-    public void onGetSuggestionsForSentence(SuggestionsInfo[] results) {
+    public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
         // TODO: Handle the position and length for each suggestion
-        onGetSuggestions(results);
+        // do nothing for now
     }
 
     @Override
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 13798ef..f66da29 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -3807,21 +3807,21 @@
             }
         }
 
-        Handler h = getHandler();
-        if (h != null) {
+        ViewRootImpl viewRootImpl = getViewRootImpl();
+        if (viewRootImpl != null) {
             long eventTime = SystemClock.uptimeMillis();
-            h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+            viewRootImpl.dispatchKeyFromIme(
                     new KeyEvent(eventTime, eventTime,
                     KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                     KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
-                    | KeyEvent.FLAG_EDITOR_ACTION)));
-            h.sendMessage(h.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+                    | KeyEvent.FLAG_EDITOR_ACTION));
+            viewRootImpl.dispatchKeyFromIme(
                     new KeyEvent(SystemClock.uptimeMillis(), eventTime,
                     KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0,
                     KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
                     KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE
-                    | KeyEvent.FLAG_EDITOR_ACTION)));
+                    | KeyEvent.FLAG_EDITOR_ACTION));
         }
     }
 
@@ -5022,15 +5022,19 @@
                     hardwareCanvas.setViewport(width, height);
                     // The dirty rect should always be null for a display list
                     hardwareCanvas.onPreDraw(null);
+                    hardwareCanvas.translate(-mScrollX, -mScrollY);
                     layout.draw(hardwareCanvas, highlight, mHighlightPaint, cursorOffsetVertical);
+                    hardwareCanvas.translate(mScrollX, mScrollY);
                 } finally {
                     hardwareCanvas.onPostDraw();
                     mTextDisplayList.end();
                     mTextDisplayListIsValid = true;
                 }
             }
-            ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList,
-                    mScrollX + width, mScrollY + height, null);
+            canvas.translate(mScrollX, mScrollY);
+            ((HardwareCanvas) canvas).drawDisplayList(mTextDisplayList, width, height, null,
+                    DisplayList.FLAG_CLIP_CHILDREN);
+            canvas.translate(-mScrollX, -mScrollY);
         } else {
             layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
         }
@@ -11407,7 +11411,7 @@
     }
 
     @Override
-    protected void resolveTextDirection() {
+    public void onResolveTextDirection() {
         if (hasPasswordTransformationMethod()) {
             mTextDir = TextDirectionHeuristics.LOCALE;
             return;
@@ -11416,9 +11420,6 @@
         // Always need to resolve layout direction first
         final boolean defaultIsRtl = (getResolvedLayoutDirection() == LAYOUT_DIRECTION_RTL);
 
-        // Then resolve text direction on the parent
-        super.resolveTextDirection();
-
         // Now, we can select the heuristic
         int textDir = getResolvedTextDirection();
         switch (textDir) {
@@ -11447,7 +11448,6 @@
      * drawables depending on the layout direction.
      *
      * A call to the super method will be required from the subclasses implementation.
-     *
      */
     protected void resolveDrawables() {
         // No need to resolve twice
diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java
index f3d891d..02dc27b 100644
--- a/core/java/android/widget/ZoomButtonsController.java
+++ b/core/java/android/widget/ZoomButtonsController.java
@@ -501,7 +501,7 @@
 
         } else {
 
-            ViewRootImpl viewRoot = getOwnerViewRootImpl();
+            ViewRootImpl viewRoot = mOwnerView.getViewRootImpl();
             if (viewRoot != null) {
                 viewRoot.dispatchKey(event);
             }
@@ -526,20 +526,6 @@
         }
     }
 
-    private ViewRootImpl getOwnerViewRootImpl() {
-        View rootViewOfOwner = mOwnerView.getRootView();
-        if (rootViewOfOwner == null) {
-            return null;
-        }
-
-        ViewParent parentOfRootView = rootViewOfOwner.getParent();
-        if (parentOfRootView instanceof ViewRootImpl) {
-            return (ViewRootImpl) parentOfRootView;
-        } else {
-            return null;
-        }
-    }
-
     /**
      * @hide The ZoomButtonsController implements the OnTouchListener, but this
      *       does not need to be shown in its public API.
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
index ba0aa1a..4553f9f 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSession.aidl
@@ -24,7 +24,7 @@
 oneway interface ISpellCheckerSession {
     void onGetSuggestionsMultiple(
             in TextInfo[] textInfos, int suggestionsLimit, boolean multipleWords);
-    void onGetSuggestionsMultipleForSentence(in TextInfo[] textInfos, int suggestionsLimit);
+    void onGetSentenceSuggestionsMultiple(in TextInfo[] textInfos, int suggestionsLimit);
     void onCancel();
     void onClose();
 }
diff --git a/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
index b44dbc8..641ed8c 100644
--- a/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
+++ b/core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl
@@ -16,6 +16,7 @@
 
 package com.android.internal.textservice;
 
+import android.view.textservice.SentenceSuggestionsInfo;
 import android.view.textservice.SuggestionsInfo;
 
 /**
@@ -23,5 +24,5 @@
  */
 oneway interface ISpellCheckerSessionListener {
     void onGetSuggestions(in SuggestionsInfo[] results);
-    void onGetSuggestionsForSentence(in SuggestionsInfo[] results);
+    void onGetSentenceSuggestions(in SentenceSuggestionsInfo[] result);
 }
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 517ce4e..2f325bf 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -606,6 +606,9 @@
                 ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) == 0 || mLogo == null)) {
             mHomeLayout.setIcon(icon);
         }
+        if (mExpandedActionView != null) {
+            mExpandedHomeLayout.setIcon(mIcon.getConstantState().newDrawable(getResources()));
+        }
     }
 
     public void setIcon(int resId) {
diff --git a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
index 2e7810f..26518eb 100644
--- a/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
+++ b/core/java/com/android/internal/widget/PasswordEntryKeyboardHelper.java
@@ -147,7 +147,7 @@
     }
 
     private void sendKeyEventsToTarget(int character) {
-        Handler handler = mTargetView.getHandler();
+        ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
         KeyEvent[] events = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD).getEvents(
                 new char[] { (char) character });
         if (events != null) {
@@ -156,22 +156,22 @@
                 KeyEvent event = events[i];
                 event = KeyEvent.changeFlags(event, event.getFlags()
                         | KeyEvent.FLAG_SOFT_KEYBOARD | KeyEvent.FLAG_KEEP_TOUCH_MODE);
-                handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY, event));
+                viewRootImpl.dispatchKey(event);
             }
         }
     }
 
     public void sendDownUpKeyEvents(int keyEventCode) {
         long eventTime = SystemClock.uptimeMillis();
-        Handler handler = mTargetView.getHandler();
-        handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+        ViewRootImpl viewRootImpl = mTargetView.getViewRootImpl();
+        viewRootImpl.dispatchKeyFromIme(
                 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_DOWN, keyEventCode, 0, 0,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
-                    KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
-        handler.sendMessage(handler.obtainMessage(ViewRootImpl.DISPATCH_KEY_FROM_IME,
+                    KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
+        viewRootImpl.dispatchKeyFromIme(
                 new KeyEvent(eventTime, eventTime, KeyEvent.ACTION_UP, keyEventCode, 0, 0,
                         KeyCharacterMap.VIRTUAL_KEYBOARD, 0,
-                        KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)));
+                        KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
     }
 
     public void onKey(int primaryCode, int[] keyCodes) {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 78e8df3..c6d3cee 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -185,6 +185,7 @@
 	libcore/include
 
 LOCAL_SHARED_LIBRARIES := \
+	libandroidfw \
 	libexpat \
 	libnativehelper \
 	libcutils \
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index ea35006..4b64bf3 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -15,8 +15,8 @@
 #include "JNIHelp.h"
 
 #include <android_runtime/AndroidRuntime.h>
-#include <utils/Asset.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/ResourceTypes.h>
 #include <netinet/in.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index d437929..682877a 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -37,7 +37,7 @@
 
 #include <binder/Parcel.h>
 #include <jni.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
 #include <sys/stat.h>
 
 #if 0
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index c1acaa3..4f64ff8 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -5,8 +5,8 @@
 #include "SkUtils.h"
 #include "CreateJavaOutputStreamAdaptor.h"
 
-#include <utils/Asset.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/ResourceTypes.h>
 #include <netinet/in.h>
 
 #if 0
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index f3b28a9..684b1c1 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "9patch"
 #define LOG_NDEBUG 1
 
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 #include <utils/Log.h>
 
 #include "SkCanvas.h"
diff --git a/core/jni/android/graphics/NinePatchImpl.cpp b/core/jni/android/graphics/NinePatchImpl.cpp
index 1d0bb506..ff0eb45 100644
--- a/core/jni/android/graphics/NinePatchImpl.cpp
+++ b/core/jni/android/graphics/NinePatchImpl.cpp
@@ -18,7 +18,7 @@
 #define LOG_TAG "NinePatch"
 #define LOG_NDEBUG 1
 
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 #include <utils/Log.h>
 
 #include "SkBitmap.h"
diff --git a/core/jni/android/graphics/NinePatchPeeker.h b/core/jni/android/graphics/NinePatchPeeker.h
index 8567e23..207536c 100644
--- a/core/jni/android/graphics/NinePatchPeeker.h
+++ b/core/jni/android/graphics/NinePatchPeeker.h
@@ -18,7 +18,7 @@
 #define NinePatchPeeker_h
 
 #include "SkImageDecoder.h"
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 
 using namespace android;
 
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index b25598a..7f4c37b 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -2,10 +2,10 @@
 #include <android_runtime/AndroidRuntime.h>
 
 #include "GraphicsJNI.h"
-#include <android_runtime/android_util_AssetManager.h>
 #include "SkStream.h"
 #include "SkTypeface.h"
-#include <utils/AssetManager.h>
+#include <android_runtime/android_util_AssetManager.h>
+#include <androidfw/AssetManager.h>
 
 using namespace android;
 
diff --git a/core/jni/android/graphics/Utils.h b/core/jni/android/graphics/Utils.h
index 9a7a697..75ceaa2 100644
--- a/core/jni/android/graphics/Utils.h
+++ b/core/jni/android/graphics/Utils.h
@@ -22,7 +22,7 @@
 #include "android_util_Binder.h"
 
 #include <jni.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
 
 namespace android {
 
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 536681b..4b3324b 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -27,7 +27,7 @@
 #include <android_runtime/android_util_AssetManager.h>
 #include <surfaceflinger/Surface.h>
 #include <ui/egl/android_natives.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 #include <utils/Looper.h>
 
 #include "JNIHelp.h"
diff --git a/core/jni/android_app_backup_FullBackup.cpp b/core/jni/android_app_backup_FullBackup.cpp
index 066a23e..2ca645a 100644
--- a/core/jni/android_app_backup_FullBackup.cpp
+++ b/core/jni/android_app_backup_FullBackup.cpp
@@ -21,7 +21,7 @@
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 
 #include <string.h>
 
diff --git a/core/jni/android_backup_BackupDataInput.cpp b/core/jni/android_backup_BackupDataInput.cpp
index 2fb0076..25b0007 100644
--- a/core/jni/android_backup_BackupDataInput.cpp
+++ b/core/jni/android_backup_BackupDataInput.cpp
@@ -20,7 +20,7 @@
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 
 namespace android
 {
diff --git a/core/jni/android_backup_BackupDataOutput.cpp b/core/jni/android_backup_BackupDataOutput.cpp
index abe0104..e8f0fb8 100644
--- a/core/jni/android_backup_BackupDataOutput.cpp
+++ b/core/jni/android_backup_BackupDataOutput.cpp
@@ -20,7 +20,7 @@
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 
 namespace android
 {
diff --git a/core/jni/android_backup_FileBackupHelperBase.cpp b/core/jni/android_backup_FileBackupHelperBase.cpp
index 0dfd8db..bb3a751 100644
--- a/core/jni/android_backup_FileBackupHelperBase.cpp
+++ b/core/jni/android_backup_FileBackupHelperBase.cpp
@@ -20,7 +20,7 @@
 #include "JNIHelp.h"
 #include <android_runtime/AndroidRuntime.h>
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 
 namespace android
 {
diff --git a/core/jni/android_bluetooth_BluetoothAudioGateway.cpp b/core/jni/android_bluetooth_BluetoothAudioGateway.cpp
old mode 100755
new mode 100644
diff --git a/core/jni/android_bluetooth_c.c b/core/jni/android_bluetooth_c.c
old mode 100755
new mode 100644
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index 8837538..5d51ee2 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -18,7 +18,7 @@
 
 #include <utils/Log.h>
 #include <utils/String8.h>
-#include <utils/ObbFile.h>
+#include <androidfw/ObbFile.h>
 
 #include "jni.h"
 #include "JNIHelp.h"
diff --git a/core/jni/android_os_Power.cpp b/core/jni/android_os_Power.cpp
index dc16990..48845f6 100644
--- a/core/jni/android_os_Power.cpp
+++ b/core/jni/android_os_Power.cpp
@@ -15,13 +15,18 @@
 ** limitations under the License.
 */
 
+#define LOG_TAG "Power-JNI"
+
 #include "JNIHelp.h"
 #include "jni.h"
 #include "android_runtime/AndroidRuntime.h"
 #include <utils/misc.h>
+#include <hardware/power.h>
 #include <hardware_legacy/power.h>
 #include <cutils/android_reboot.h>
 
+static struct power_module *sPowerModule;
+
 namespace android
 {
 
@@ -65,7 +70,9 @@
 static int
 setScreenState(JNIEnv *env, jobject clazz, jboolean on)
 {
-    return set_screen_state(on);
+    if (sPowerModule)
+        sPowerModule->setInteractive(sPowerModule, on);
+    return 0;
 }
 
 static void android_os_Power_shutdown(JNIEnv *env, jobject clazz)
@@ -85,12 +92,26 @@
     jniThrowIOException(env, errno);
 }
 
+static int android_os_Power_init(JNIEnv *env, jobject clazz)
+{
+    status_t err = hw_get_module(POWER_HARDWARE_MODULE_ID,
+        (hw_module_t const**)&sPowerModule);
+    ALOGE_IF(err, "couldn't load %s module (%s)",
+             POWER_HARDWARE_MODULE_ID, strerror(-err));
+
+    if (!err)
+        sPowerModule->init(sPowerModule);
+
+    return err;
+}
+
 static JNINativeMethod method_table[] = {
     { "acquireWakeLock", "(ILjava/lang/String;)V", (void*)acquireWakeLock },
     { "releaseWakeLock", "(Ljava/lang/String;)V", (void*)releaseWakeLock },
     { "setLastUserActivityTimeout", "(J)I", (void*)setLastUserActivityTimeout },
     { "setScreenState", "(Z)I", (void*)setScreenState },
     { "shutdown", "()V", (void*)android_os_Power_shutdown },
+    { "powerInitNative", "()I", (void*)android_os_Power_init },
     { "rebootNative", "(Ljava/lang/String;)V", (void*)android_os_Power_reboot },
 };
 
diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp
index 9292fc0..8a69ba4 100644
--- a/core/jni/android_server_BluetoothEventLoop.cpp
+++ b/core/jni/android_server_BluetoothEventLoop.cpp
@@ -164,7 +164,6 @@
         ALOGE("%s: out of memory!", __FUNCTION__);
         return;
     }
-    memset(nat, 0, sizeof(native_data_t));
 
     pthread_mutex_init(&(nat->thread_mutex), NULL);
 
@@ -722,24 +721,20 @@
         return JNI_FALSE;
     }
 
-    nat->pollData = (struct pollfd *)malloc(sizeof(struct pollfd) *
-            DEFAULT_INITIAL_POLLFD_COUNT);
+    nat->pollData = (struct pollfd *)calloc(
+            DEFAULT_INITIAL_POLLFD_COUNT, sizeof(struct pollfd));
     if (!nat->pollData) {
         ALOGE("out of memory error starting EventLoop!");
         goto done;
     }
 
-    nat->watchData = (DBusWatch **)malloc(sizeof(DBusWatch *) *
-            DEFAULT_INITIAL_POLLFD_COUNT);
+    nat->watchData = (DBusWatch **)calloc(
+            DEFAULT_INITIAL_POLLFD_COUNT, sizeof(DBusWatch *));
     if (!nat->watchData) {
         ALOGE("out of memory error starting EventLoop!");
         goto done;
     }
 
-    memset(nat->pollData, 0, sizeof(struct pollfd) *
-            DEFAULT_INITIAL_POLLFD_COUNT);
-    memset(nat->watchData, 0, sizeof(DBusWatch *) *
-            DEFAULT_INITIAL_POLLFD_COUNT);
     nat->pollDataSize = DEFAULT_INITIAL_POLLFD_COUNT;
     nat->pollMemberCount = 1;
 
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 17130af..7146667 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -31,9 +31,9 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
 
-#include <utils/Asset.h>
-#include <utils/AssetManager.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
 
 #include <stdio.h>
 
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index 958ddb2..28746ce 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -23,7 +23,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
 
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 
 #include <stdio.h>
 
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index 45728db..ad6033b 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -19,12 +19,11 @@
 
 #include "jni.h"
 #include "JNIHelp.h"
-#include <utils/misc.h>
 #include <android_runtime/AndroidRuntime.h>
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
 #include <utils/Log.h>
-
-#include <utils/ResourceTypes.h>
+#include <utils/misc.h>
 
 #include <stdio.h>
 
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index e19bb38..cdce4f9 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -24,7 +24,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
 #include <cutils/properties.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 
 #include <gui/SurfaceTexture.h>
 
@@ -652,9 +652,9 @@
 
 static bool android_view_GLES20Canvas_drawDisplayList(JNIEnv* env,
         jobject clazz, OpenGLRenderer* renderer, DisplayList* displayList,
-        jint width, jint height, jobject dirty) {
+        jint width, jint height, jobject dirty, jint flags) {
     android::uirenderer::Rect bounds;
-    bool redraw = renderer->drawDisplayList(displayList, width, height, bounds);
+    bool redraw = renderer->drawDisplayList(displayList, width, height, bounds, flags);
     if (redraw && dirty != NULL) {
         env->CallVoidMethod(dirty, gRectClassInfo.set,
                 int(bounds.left), int(bounds.top), int(bounds.right), int(bounds.bottom));
@@ -901,7 +901,7 @@
     { "nGetDisplayListSize",     "(I)I",       (void*) android_view_GLES20Canvas_getDisplayListSize },
     { "nSetDisplayListName",     "(ILjava/lang/String;)V",
                                                (void*) android_view_GLES20Canvas_setDisplayListName },
-    { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;)Z",
+    { "nDrawDisplayList",        "(IIIILandroid/graphics/Rect;I)Z",
                                                (void*) android_view_GLES20Canvas_drawDisplayList },
 
     { "nCreateDisplayListRenderer", "()I",     (void*) android_view_GLES20Canvas_createDisplayListRenderer },
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 6d783de..8350e73 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -21,7 +21,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <binder/Parcel.h>
 #include <utils/Log.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 #include "android_view_InputChannel.h"
 #include "android_util_Binder.h"
 
diff --git a/core/jni/android_view_InputChannel.h b/core/jni/android_view_InputChannel.h
index fa2d282..0967021 100644
--- a/core/jni/android_view_InputChannel.h
+++ b/core/jni/android_view_InputChannel.h
@@ -19,7 +19,7 @@
 
 #include "jni.h"
 
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 
 namespace android {
 
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 47b3f66..e7d4244 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -28,7 +28,7 @@
 #include <utils/Log.h>
 #include <utils/Looper.h>
 #include <utils/threads.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 #include "android_os_MessageQueue.h"
 #include "android_view_InputChannel.h"
 #include "android_view_KeyEvent.h"
@@ -264,7 +264,7 @@
     sp<NativeInputEventReceiver> receiver =
             reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
     status_t status = receiver->finishInputEvent(seq, handled);
-    if (status) {
+    if (status && status != DEAD_OBJECT) {
         String8 message;
         message.appendFormat("Failed to finish input event.  status=%d", status);
         jniThrowRuntimeException(env, message.string());
@@ -275,7 +275,7 @@
     sp<NativeInputEventReceiver> receiver =
             reinterpret_cast<NativeInputEventReceiver*>(receiverPtr);
     status_t status = receiver->consumeEvents(true /*consumeBatches*/);
-    if (status) {
+    if (status && status != DEAD_OBJECT) {
         String8 message;
         message.appendFormat("Failed to consume batched input event.  status=%d", status);
         jniThrowRuntimeException(env, message.string());
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index b9f3738..7245d9d 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
 */
 
-#include <ui/KeyCharacterMap.h>
-#include <ui/Input.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/Input.h>
 
 #include <android_runtime/AndroidRuntime.h>
 #include <nativehelper/jni.h>
diff --git a/core/jni/android_view_KeyEvent.cpp b/core/jni/android_view_KeyEvent.cpp
index 27469a2..36a98f9 100644
--- a/core/jni/android_view_KeyEvent.cpp
+++ b/core/jni/android_view_KeyEvent.cpp
@@ -20,7 +20,7 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include "android_view_KeyEvent.h"
 
 namespace android {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 2def1d1..0fb1b17 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -20,7 +20,7 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include "android_view_MotionEvent.h"
 #include "android_util_Binder.h"
 #include "android/graphics/Matrix.h"
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index 0da90d7..668d3bb 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -20,7 +20,7 @@
 
 #include <android_runtime/AndroidRuntime.h>
 #include <utils/Log.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include "android_view_MotionEvent.h"
 
 
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index b68c97a..afbcfc2 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -21,7 +21,7 @@
 
 #include <utils/Log.h>
 #include <ScopedUtfChars.h>
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipFileRO.h>
 
 #include <zlib.h>
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 68c919e..a2b1117 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1521,6 +1521,17 @@
         android:description="@string/permdesc_serialPort"
         android:protectionLevel="normal" />
 
+    <!-- Allows the holder to access content providers from outside an ApplicationThread.
+         This permission is enforced by the ActivityManagerService on the corresponding APIs,
+         in particular ActivityManagerService#getContentProviderExternal(String) and
+         ActivityManagerService#removeContentProviderExternal(String).
+         @hide
+    -->
+    <permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY"
+        android:label="@string/permlab_accessContentProvidersExternally"
+        android:description="@string/permdesc_accessContentProvidersExternally"
+        android:protectionLevel="signature" />
+
     <!-- The system process is explicitly the only one allowed to launch the
          confirmation UI for full backup/restore -->
     <uses-permission android:name="android.permission.CONFIRM_FULL_BACKUP"/>
diff --git a/core/res/assets/webkit/youtube.html b/core/res/assets/webkit/youtube.html
index d808bcf..8e103c1 100644
--- a/core/res/assets/webkit/youtube.html
+++ b/core/res/assets/webkit/youtube.html
@@ -13,94 +13,59 @@
         height: 100%;
         padding: 0%;
         z-index: 10;
+        background-size: 100%;
+        background: no-repeat;
+        background-position: center;
+      }
+      #play {
+        position: absolute;
+        left: 50%;
+        top: 50%;
+      }
+      #logo {
+        position: absolute;
+        bottom: 0;
+        right: 0;
       }
     </style>
   </head>
   <body id="body">
   <script type="text/javascript">
-    // Nominal original size. If the embed is smaller than this, the play and logo
-    // images get scaled appropriately. These are actually 3/4 of the sizes suggested
-    // by youtube, so the images don't get too tiny.
-    defHeight = 258;
-    defWidth = 318;
-
     function setup() {
         var width = document.body.clientWidth;
         var height = document.body.clientHeight;
-        var canvas = document.getElementById("canvas");
-        // Resize the canvas to the right size
-        canvas.width = width;
-        canvas.height = height;
-        var ctx = canvas.getContext('2d');
+        var mainElement = document.getElementById("main");
+        var playElement = document.getElementById("play");
         var loadcount = 0;
+        var POSTER = "http://img.youtube.com/vi/VIDEO_ID/0.jpg";
+
         function doload() {
-            if (++loadcount == 3) {
-                // All images are loaded, so display them.
-                // (Note that the images are loaded from javascript, so might load
-                // after document.onload fires)
-
-                playWidth = play.width;
-                playHeight = play.height;
-                logoWidth = logo.width;
-                logoHeight = logo.height;
-                var ratio = 1;
-                // If the page is smaller than it 'should' be in either dimension
-                // we scale the background, play button and logo according to the
-                // dimension that has been shrunk the most.
-                if (width / height > defWidth / defHeight && height < defHeight) {
-                    ratio = height / defHeight;
-                    // Stretch the background in this dimension only.
-                    backgroundHeight = background.height / ratio;
-                    ctx.drawImage(background, 0, 0, background.width, background.height,
-                        0, (height - backgroundHeight) / 2, width, backgroundHeight);
-                } else if (width / height < defWidth / defHeight && width < defWidth) {
-                    ratio = width / defWidth;
-                    backgroundWidth = background.width / ratio;
-                    ctx.drawImage(background, 0, 0, background.width, background.height,
-                        (width - backgroundWidth) / 2, 0, backgroundWidth, height);
-                } else {
-                    // In this case stretch the background in both dimensions to fill the space.
-                    ctx.drawImage(background, 0, 0, width, height);
-                }
-                playWidth *= ratio;
-                playHeight *= ratio;
-                logoWidth *= ratio;
-                logoHeight *= ratio;
-                playLeft = (width - playWidth) / 2;
-                playTop = (height - playHeight) / 2;
-                ctx.drawImage(play, playLeft, playTop, playWidth, playHeight);
-                ctx.globalAlpha = 0.7
-                ctx.drawImage(logo, width - logoWidth, height - logoHeight, logoWidth, logoHeight);
-                // To make it slightly easier to hit, the click target is twice the width/height of the unscaled play button
-                targetLeft = width / 2 - play.width;
-                targetRight = width / 2 + play.width;
-                targetTop = height / 2 - play.height;
-                targetBottom = height / 2 + play.height;
-
-                canvas.addEventListener("click", function(e) {
-                   var posx = e.clientX-canvas.offsetLeft;
-                   var posy = e.clientY-canvas.offsetTop;
-                   if (posx >= targetLeft && posx <= targetRight &&
-                       posy >= targetTop && posy <= targetBottom) {
-                       top.location.href = "vnd.youtube:VIDEO_ID";
-                   }
-               }, false);
+            if (++loadcount == 2) {
+                // Resize the element to the right size
+                mainElement.width = width;
+                mainElement.height = height;
+                mainElement.style.backgroundImage = "url('" + POSTER + "')";
+                // Center the play button
+                playElement.style.marginTop = "-" + play.height/2 + "px";
+                playElement.style.marginLeft = "-" + play.width/2 + "px";
+                playElement.addEventListener("click", function(e) {
+                    top.location.href = "vnd.youtube:VIDEO_ID";
+                }, false);
             }
         }
         var background = new Image();
         background.onload = doload;
-        background.src = "http://img.youtube.com/vi/VIDEO_ID/0.jpg";
+        background.src = POSTER;
         play = new Image();
         play.onload = doload;
         play.src = "play.png";
-        logo = new Image();
-        logo.onload = doload;
-        logo.src = "youtube.png";
     }
+
     window.onload = setup;
   </script>
     <div id="main">
-    <canvas id="canvas"></canvas>
+        <img src="play.png" id="play"></img>
+        <img src="youtube.png" id="logo"></img>
     </div>
   </body>
 </html>
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
index f58a19c..cb08eed 100644
--- a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
index 744b1fa..ea065c3 100644
--- a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
+++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..d3ba98c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..153c6ad
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..ec6bc54
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..9fd4f33
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 840323e..6f861fb 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -766,6 +766,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Laat die houer toe om versoeke aan pakketverifieerders te rig. Dit moet nooit vir normale programme nodig wees nie."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"kry toegang tot reekspoorte"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Laat die houer toe om toegang te verkry tot reekspoorte wat die SerialManager API gebruik."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Wil jy hê die blaaier moet hierdie wagwoord onthou?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nie nou nie"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Onthou"</string>
@@ -975,6 +979,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kon nie aan Wi-Fikoppel nie"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" het \'n swak internetverbinding."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Begin Wi-Fi Direct. Dit sal die Wi-Fi-kliënt/warmkol afskakel."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kon nie Wi-Fi Direct begin nie."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direk is aan"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Raak vir instellings"</string>
     <string name="accept" msgid="1645267259272829559">"Aanvaar"</string>
     <string name="decline" msgid="2112225451706137894">"Weier"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging gestuur"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 905b90c..bb6246a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"የፓኬጅ አረጋጋጮችን ጥየቃ ለማድረግ ያዡ ይፈቅዳሉ። ለመደበኛ ትግበራዎች በፍፁም አያስፈልግም።"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"ተከታታይ ወደቦችን ድረስ"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API. የተከታታይ አደራጅ APIን በመጠቀም ያዡ የተከታታይ ወደቦችን እንዲደርስ ይፈቅዳል።"</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"አሳሹ ይህን ይለፍ ቃል እንዲያስታወስ ይፈልጋሉ?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"አሁን አይደለም"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"አስታውስ"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ወደ Wi-Fi ለማያያዝ አልተቻለም"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ደካማ የበይነመረብ ግንኙነት ኣለው።"</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ቀጥታ"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"የWi-Fi በቀጥታ  ጀምር።ይህ የWi-Fi ደንበኛ /ድረስ ነጥብ  ያጠፋል።"</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"በቀጥታ Wi-Fi ማስጀመር አልተቻለም።"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"የWi-Fi ቀጥታ በርቷል"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"ለቅንብሮች ንካ"</string>
     <string name="accept" msgid="1645267259272829559">"ተቀበል"</string>
     <string name="decline" msgid="2112225451706137894">"ውድቅ አድርግ"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ግብዣ ተልኳል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index a7c37e7..580f9bc 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"السماح للمالك بإجراء طلبات محققي الحزمة. لن تكون هناك حاجة إليه مطلقًا مع التطبيقات العادية."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"الدخول إلى المنافذ التسلسلية"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"يسمح لحامله بالدخول إلى المنافذ التسلسلية باستخدام واجهة برمجة التطبيقات."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"هل تريد من المتصفح تذكر كلمة المرور هذه؟"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"ليس الآن"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"تذكّر"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"تعذر الاتصال بـ Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" لديها اتصال إنترنت رديء."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"اتصال Wi-Fi مباشر"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"ابدأ Wi-Fi Direct. يؤدي هذا إلى إيقاف عميل/نقطة اتصال Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"تعذر بدء Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"تم تشغيل اتصال Wi-Fi المباشر"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"المس للحصول على الإعدادات"</string>
     <string name="accept" msgid="1645267259272829559">"قبول"</string>
     <string name="decline" msgid="2112225451706137894">"رفض"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"تم إرسال الدعوة"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 4a226a1..8de1cf5 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дазваляе ўладальніку рабіць запыты верыфікатараў пакету. Не патрабуецца для звычайных прыкладанняў."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"атрымаць доступ да паслядоўных партоў"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Дазваляе ўладальніку атрымліваць доступ да паслядоўных партоў з дапамогай API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Вы хочаце, каб браўзэр запомніў гэты пароль?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не цяпер"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запомніць"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Немагчыма падключыцца да Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" дрэннае падключэнне да Інтэрнэту."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Пачаць работу Wi-Fi Direct. Гэта адключыць кліента або кропку доступу Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Немагчыма запусціць Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct уключаны"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Дакраніцеся, каб наладзіць"</string>
     <string name="accept" msgid="1645267259272829559">"Прыняць"</string>
     <string name="decline" msgid="2112225451706137894">"Адхіліць"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрашэнне адпраўлена"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index f311a28..ec2e0bf 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Разрешава на притежателя да прави заявки за верификатори на пакета. Нормалните приложения би трябвало никога да не се нуждаят от това."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"достъп до серийни портове"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Разрешава на притежателя достъп до серийни портове посредством приложния програмен интерфейс (API) SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Искате ли браузърът да запомни тази парола?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не сега"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запомняне"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не можа да се свърже с Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лоша връзка с интернет."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Стартиране на Wi-Fi Direct. Това ще изключи клиентската програма/точката за достъп до Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct не можа да се стартира."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct е включено"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Докоснете за настройки"</string>
     <string name="accept" msgid="1645267259272829559">"Приемам"</string>
     <string name="decline" msgid="2112225451706137894">"Отхвърлям"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Поканата е изпратена"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 95dae9d..173f1fc 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet que el titular sol·liciti verificadors de paquets. No s\'hauria de necessitar mai per a les aplicacions normals."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"accedeix a ports sèrie"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet que el titular accedeixi a ports sèrie amb l\'API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Voleu que el navegador recordi aquesta contrasenya?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ara no"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Recorda-ho"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No s\'ha pogut connectar a la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" té una mala connexió a Internet."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Inicia Wi-Fi Direct. Això desactivarà el client/la zona Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No s\'ha pogut iniciar Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct està activat"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca per accedir a la configuració"</string>
     <string name="accept" msgid="1645267259272829559">"Accepta"</string>
     <string name="decline" msgid="2112225451706137894">"Rebutja"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"S\'ha enviat la invitació"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index c01526d..d3b5276 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteli podávat žádosti o ověření balíčků. Běžné aplikace by toto oprávnění neměly nikdy požadovat."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"přístup k sériovým portům"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Umožňuje držiteli přístup k sériovým portům pomocí rozhraní SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prohlížeč zapamatoval toto heslo?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nyní ne"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamatovat"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Připojení k síti Wi-Fi se nezdařilo"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má pomalé připojení k internetu."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Přímé připojení sítě Wi-Fi"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustit přímé připojení sítě Wi-Fi. Tato možnost vypne provoz sítě Wi-Fi v režimu klient/hotspot."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Přímé připojení sítě Wi-Fi se nepodařilo spustit."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Přímé připojení sítě Wi-Fi je zapnuto"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavení otevřete dotykem"</string>
     <string name="accept" msgid="1645267259272829559">"Přijmout"</string>
     <string name="decline" msgid="2112225451706137894">"Odmítnout"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka odeslána."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4904a99..78aff33 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -757,13 +757,17 @@
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"tilføj telefonsvarer"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"Tillader, at appen kan tilføje beskeder på din telefonsvarer."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"skifte tilladelser til geografisk placering i Browser"</string>
-    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websteder."</string>
+    <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"Tillader, at appen kan ændre browserens tilladelser angående geografisk placering. Ondsindede apps kan benytte dette til at sende oplysninger om placering til vilkårlige websites."</string>
     <string name="permlab_packageVerificationAgent" msgid="5568139100645829117">"bekræft pakker"</string>
     <string name="permdesc_packageVerificationAgent" msgid="8437590190990843381">"Tillader, at appen kan bekræfte, at en pakke kan installeres."</string>
     <string name="permlab_bindPackageVerifier" msgid="4187786793360326654">"bind til en bekræftelse af pakker"</string>
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillader, at indehaveren kan sende anmodninger om bekræftelser af pakker. Dette bør aldrig være nødvendigt for almindelige apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"adgang til serielle porte"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Tillader, at indehaveren kan få adgang til serielle porte ved hjælp af SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Ønsker du, at browseren skal huske denne adgangskode?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kunne ikke oprette forbindelse til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig internetforbindelse."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette slår Wi-Fi-klient/hotspot fra."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct kunne ikke startes."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slået til"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryk for indstillinger"</string>
     <string name="accept" msgid="1645267259272829559">"Accepter"</string>
     <string name="decline" msgid="2112225451706137894">"Afvis"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitationen er sendt"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 20ef4d7..78845c4 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ermöglicht dem Halter, Anfragen für die Paketprüfung zu senden. Sollte nie für normale Apps benötigt werden."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"Zugriff auf serielle Schnittstellen"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Ermöglicht dem Inhaber den Zugriff auf serielle Schnittstellen über das SerialManager-API"</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Es konnte keine WLAN-Verbindung hergestellt werden."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" hat eine schlechte Internetverbindung."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct-Betrieb starten. Hierdurch wird der WLAN-Client-/-Hotspot-Betrieb deaktiviert."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Starten von Wi-Fi Direct nicht möglich"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ist aktiviert."</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Zum Aufrufen der Einstellungen berühren"</string>
     <string name="accept" msgid="1645267259272829559">"Akzeptieren"</string>
     <string name="decline" msgid="2112225451706137894">"Ablehnen"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Einladung gesendet"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 200f702..9244dab 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Επιτρέπει στον κάτοχο να υποβάλλει ερωτήματα σε προγράμματα επαλήθευσης πακέτου. Δεν απαιτείται για συνήθεις εφαρμογές."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"πρόσβαση στις σειριακές θύρες"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Επιτρέπει στον κάτοχο την πρόσβαση στις σειριακές θύρες με τη χρήση του SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Θέλετε το πρόγραμμα περιήγησης να διατηρήσει αυτόν τον κωδικό πρόσβασης;"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Να μην γίνει τώρα"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Διατήρηση"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Δεν είναι δυνατή η σύνδεση στο Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" έχει κακή σύνδεση στο Διαδίκτυο."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Ξεκινήστε τη λειτουργία Wi-Fi Direct. Θα απενεργοποιηθεί η λειτουργία πελάτη/φορητού σημείου πρόσβασης Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Δεν ήταν δυνατή η εκκίνηση του Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Το Wi-Fi Direct έχει ενεργοποιηθεί"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Αγγίξτε για ρυθμίσεις"</string>
     <string name="accept" msgid="1645267259272829559">"Αποδοχή"</string>
     <string name="decline" msgid="2112225451706137894">"Απόρριψη"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Η πρόσκληση στάλθηκε"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 2859942..dbd2218 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Allows the holder to make requests of package verifiers. Should never be needed for normal apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"access serial ports"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Allows the holder to access serial ports using the SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Do you want the browser to remember this password?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Not now"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Remember"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Couldn\'t connect to Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" has a poor Internet connection."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. This will turn off Wi-Fi client/hotspot."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Couldn\'t start Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is on"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Touch for settings"</string>
     <string name="accept" msgid="1645267259272829559">"Accept"</string>
     <string name="decline" msgid="2112225451706137894">"Decline"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation sent"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index dbc96e7..42cc24a 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que el titular solicite verificadores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"Acceder a los puertos serie"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de la API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"¿Quieres recordar esta contraseña en el navegador?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no."</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Recuerda"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se pudo conectar a la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una mala conexión a Internet."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se pudo iniciar Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Se activó Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para ajustar los parámetros de configuración"</string>
     <string name="accept" msgid="1645267259272829559">"Aceptar"</string>
     <string name="decline" msgid="2112225451706137894">"Rechazar"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Se envió la invitación."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index d3c55a6..a09a6bf 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que se envíen solicitudes de detectores de paquetes. Las aplicaciones normales no deberían necesitar este permiso."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"acceder a puertos serie"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite acceder a puertos serie a través de SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"¿Quieres que el navegador recuerde esta contraseña?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ahora no"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Recordar"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"No se ha podido establecer conexión con la red Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tiene una conexión inestable a Internet."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar Wi-Fi Direct. Se desactivará el funcionamiento de la zona o del cliente Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"No se ha podido iniciar Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activado"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toca para acceder a Ajustes"</string>
     <string name="accept" msgid="1645267259272829559">"Aceptar"</string>
     <string name="decline" msgid="2112225451706137894">"Rechazar"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitación enviada"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index c3a6169..07e732a 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lubab omanikul teha taotlusi paketi kinnitajate kohta. Tavarakenduste puhul ei peaks seda kunagi vaja minema."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"juurdepääs jadaportidele"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Võimaldab omanikul SerialManageri API-liidese abil jadaportidele juurde pääseda."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Kas soovite, et brauser jätaks selle parooli meelde?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Mitte praegu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Pidage meeles"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ei saanud WiFi-ga ühendust"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" on halb Interneti-ühendus."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"WiFi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käivitage WiFi otseühendus. See lülitab välja WiFi kliendi/leviala."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"WiFi otseühenduse käivitamine ebaõnnestus."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"WiFi Direct on sees"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Puuted seadete jaoks"</string>
     <string name="accept" msgid="1645267259272829559">"Nõustu"</string>
     <string name="decline" msgid="2112225451706137894">"Keeldu"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutse on saadetud"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 87eee68..ddb0438 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"به دارنده اجازه می‎دهد تا تاییدکنندگان بسته را درخواست کند. برای برنامه‎های عادی نیاز نیست."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"دسترسی به درگاه‌های سریال"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"به دارنده اجازه می‌دهد با استفاده از SerialManager API به درگاه‌های سریال دسترسی داشته باشد."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"می خواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"اکنون خیر"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"اتصال به Wi-Fi ممکن نیست"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" اتصال اینترنتی ضعیفی دارد."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct را شروع کنید. این کار نقطه اتصال/سرویس گیرنده Wi-Fi را غیرفعال خواهد کرد."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct شروع نشد."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct روشن است"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"لمس کردن برای تنظیمات"</string>
     <string name="accept" msgid="1645267259272829559">"پذیرش"</string>
     <string name="decline" msgid="2112225451706137894">"عدم پذیرش"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"دعوت‌نامه ارسال شد"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5ab7158..b837c5a 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Antaa sovelluksen tehdä pakettien vahvistuspyyntöjä. Ei tavallisten sovellusten käyttöön."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"käytä sarjaportteja"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Luvan haltija voi käyttää sarjaportteja SerialManager-sovellusliittymän avulla."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Haluatko selaimen muistavan tämän salasanan?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ei nyt"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Muista"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wifi-yhteyden muodostaminen epäonnistui"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" : huono internetyhteys."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Suora wifi-yhteys"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Käynnistä suora wifi-yhteys. Wifi-asiakas/-hotspot poistetaan käytöstä."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Suoran wifi-yhteyden käynnistäminen epäonnistui."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct on käytössä"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tarkastele asetuksia koskettamalla"</string>
     <string name="accept" msgid="1645267259272829559">"Hyväksy"</string>
     <string name="decline" msgid="2112225451706137894">"Hylkää"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Kutsu lähetetty."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 6067350..aebe460 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permet à l\'application autorisée d\'effectuer des requêtes de vérificateurs de package. Les applications standards ne doivent jamais avoir recours à cette fonctionnalité."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"accéder aux ports série"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permet à l\'application autorisée d\'accéder aux ports série avec l\'API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Voulez-vous que le navigateur se souvienne de ce mot de passe ?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Pas maintenant"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Mémoriser"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossible de se connecter au Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" dispose d\'une mauvaise connexion Internet."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Lancer le Wi-Fi Direct. Cela désactive le fonctionnement du Wi-Fi client ou via un point d\'accès."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Impossible d\'activer le Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct activé"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Appuyez pour accéder aux paramètres."</string>
     <string name="accept" msgid="1645267259272829559">"Accepter"</string>
     <string name="decline" msgid="2112225451706137894">"Refuser"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitation envoyée"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 1aaedbd..11bad07 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"धारक को पैकेज प्रमाणक के अनुरोध की अनुमति‍ देता है. सामान्‍य एप्‍लिकेशन के लिए कभी भी आवश्‍यक नहीं होना चाहिए."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"सीरियल पोर्ट पर पहुंचें"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API का उपयोग करके धारक को सीरियल पोर्ट पर पहुंच प्रदान करता है."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"क्‍या आप चाहते हैं कि ब्राउज़र पासवर्ड को याद रखे?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"अभी नहीं"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"याद रखें"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi से कनेक्‍ट नहीं हो सका"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" के पास एक कमज़ोर इंटरनेट कनेक्‍शन है."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi प्रत्यक्ष"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi डायरेक्ट प्रारंभ करें. इससे Wi-Fi क्‍लाइंट/हॉटस्पॉट कार्यवाही बंद हो जाएगी."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi डायरेक्ट प्रारंभ नहीं किया जा सका."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi प्रत्यक्ष चालू है"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"सेटिंग के लिए स्‍पर्श करें"</string>
     <string name="accept" msgid="1645267259272829559">"स्वीकार करें"</string>
     <string name="decline" msgid="2112225451706137894">"अस्वीकार करें"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"आमंत्रण भेजा गया"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 0775984..462cb52 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -215,8 +215,8 @@
     <string name="permdesc_reorderTasks" msgid="4175137612205663399">"Omogućuje aplikaciji da premjesti zadatke u prednji plan ili pozadinu. Zlonamjerne aplikacije mogu na silu doći u prednji plan bez vašeg nadzora."</string>
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zaustavljanje pokrenutih aplikacija"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Omogućuje aplikaciji uklanjanje zadataka i uklanjanje njihovih aplikacija. Zlonamjerne aplikacije mogu poremetiti rad drugih aplikacija."</string>
-    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje zaslona kompatibilnost"</string>
-    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Aplikaciji omogućuje upravljanje načinom kompatibilnosti zaslona drugih aplikacija. Zlonamjerne aplikacije mogu prekinuti takvo ponašanje ostalih aplikacija."</string>
+    <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"postavljanje kompatibilnosti sa zaslonom"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Aplikaciji omogućuje upravljanje načinom kompatibilnosti aplikacija sa zaslonom. Zlonamjerne aplikacije mogu prekinuti takvo ponašanje ostalih aplikacija."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"omogućavanje rješavanja programskih pogrešaka u aplikaciji"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Omogućuje aplikaciji uključivanje uklanjanja programskih pogrešaka za drugu aplikaciju. Zlonamjerne aplikacije mogu na taj način ukloniti druge aplikacije."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"promjena postavki korisničkog sučelja"</string>
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Nositelju omogućuje da traži paketnu provjeru. Ne bi smjelo biti potrebno za normalne aplikacije."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"pristup serijskim priključcima"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Rukovatelju omogućuje pristup serijskim priključcima pomoću značajke SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Želite li da preglednik zapamti ovu zaporku?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne sada"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamti"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ne može se spojiti na Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima lošu internetsku vezu."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Izravni Wi-Fi"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Pokreni izravan rad s Wi-Fi mrežom. To će isključiti rad s Wi-Fi klijentom/žarišnom točkom."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Pokretanje izravne Wi-Fi veze nije moguće."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct uključen"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dodirnite za postavke"</string>
     <string name="accept" msgid="1645267259272829559">"Prihvaćam"</string>
     <string name="decline" msgid="2112225451706137894">"Odbaci"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozivnica je poslana"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index e125ba8..c74ef36 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lehetővé teszi, hogy a tulajdonos kérelmeket nyújtson be a csomag hitelesítőivel kapcsolatban. A normál alkalmazásoknak erre soha nincs szüksége."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"soros portok elérése"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Lehetővé teszi a tulajdonos számára a soros portok elérését a SerialManager API segítségével."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Szeretné, hogy a böngésző megjegyezze a jelszót?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Most nem"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Megjegyzés"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nem sikerült csatlakozni a Wi-Fi hálózathoz"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" rossz internetkapcsolattal rendelkezik."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct elindítása. A Wi-Fi kliens/hotspot ettől leáll."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nem sikerült elindítani a Wi-Fi Direct kapcsolatot."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"A Wi-Fi Direct be van kapcsolva"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"A beállításokhoz érintse meg"</string>
     <string name="accept" msgid="1645267259272829559">"Elfogadás"</string>
     <string name="decline" msgid="2112225451706137894">"Elutasítás"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Meghívó elküldve"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 72fcb50..068356e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Mengizinkan pemegang mengajukan permintaan pemverifikasian paket. Tidak pernah dibutuhkan oleh apl normal."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"akses port serial"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Memungkinkan pemegangnya mengakses port serial menggunakan API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Apakah Anda ingin peramban menyimpan sandi ini?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Tidak sekarang"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak dapat tersambung ke Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" memiliki sambungan internet yang buruk."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Memulai Wi-Fi Langsung. Opsi ini akan mematikan hotspot/klien Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulai Wi-Fi Langsung."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Langsung aktif"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk setelan"</string>
     <string name="accept" msgid="1645267259272829559">"Terima"</string>
     <string name="decline" msgid="2112225451706137894">"Tolak"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Undangan terkirim"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ec9457b..221fff0 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Consente al proprietario di effettuare richieste relative alle verifiche dei pacchetti. Non dovrebbe mai essere necessario per le normali applicazioni."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"accesso alle porte seriali"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permette al proprietario di accedere alle porte seriali utilizzando l\'API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Memorizzare la password nel browser?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Non ora"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Memorizza"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Impossibile connettersi alla rete Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ha una connessione Internet debole."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Avvia Wi-Fi Direct. Verrà disattivato il client/hotspot Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Avvio di Wi-Fi Direct non riuscito."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct è attivo"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocca per le impostazioni"</string>
     <string name="accept" msgid="1645267259272829559">"Accetto"</string>
     <string name="decline" msgid="2112225451706137894">"Rifiuto"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invito inviato"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 5fc15c7..c1d7d82 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"מאפשר למשתמש להגיש בקשות של מאמתי חבילות. הרשאה זו לעולם אינה נחוצה ליישומים רגילים."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"גישה ליציאות טוריות"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"מאפשר לבעלים לגשת ליציאות טוריות באמצעות ממשק ה- API של SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"האם ברצונך שהדפדפן יזכור סיסמה זו?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"לא כעת"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"זכור"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"אין אפשרות להתחבר ל-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" אינו מחובר היטב לאינטרנט."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi ישיר"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"הפעל Wi-Fi ישיר. פעולה זו תכבה את הלקוח/הנקודה החמה של ה-Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"לא ניתן להפעיל Wi-Fi ישיר"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ישיר מופעל"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"גע עבור הגדרות"</string>
     <string name="accept" msgid="1645267259272829559">"קבל"</string>
     <string name="decline" msgid="2112225451706137894">"דחה"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ההזמנה נשלחה"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 63b8c73..b3476db 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -216,7 +216,7 @@
     <string name="permlab_removeTasks" msgid="6821513401870377403">"実行中のアプリの停止"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"タスクの削除とアプリの終了をアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、他のアプリの動作が妨害される恐れがあります。"</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"画面互換性の設定"</string>
-    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"他のアプリケーションの画面互換性モードをコントロールすることをアプリに許可します。この許可を悪意のあるアプリケーションに利用されると、他のアプリケーションの動作が中断される恐れがあります。"</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"他のアプリの画面互換性モードをコントロールすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリの動作が中断される恐れがあります。"</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"アプリのデバッグの有効化"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"別のアプリをデバッグモードにすることをアプリに許可します。この許可を悪意のあるアプリに利用されると、他のアプリが強制終了される恐れがあります。"</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI設定の変更"</string>
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"パッケージベリファイアのリクエストを所有者に許可します。通常のアプリでは不要です。"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"シリアルポートへのアクセス"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager APIを使用してシリアルポートにアクセスすることを所有者に許可します。"</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"このパスワードをブラウザで保存しますか?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"今は保存しない"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"保存"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fiに接続できませんでした"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" はインターネット接続に問題があります。"</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Directを開始します。これによりWi-Fiクライアント/アクセスポイントがOFFになります。"</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Directを開始できませんでした。"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi DirectはONです"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"設定を表示するにはタップしてください"</string>
     <string name="accept" msgid="1645267259272829559">"同意する"</string>
     <string name="decline" msgid="2112225451706137894">"同意しない"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"招待状を送信しました"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index f97cbdc..aeca1ed 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"권한을 가진 프로그램이 패키지 인증을 요청할 수 있도록 허용합니다. 일반 앱에는 필요하지 않습니다."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"직렬 포트에 액세스"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"SerialManager API를 사용하여 권한을 가진 프로그램이 직렬 포트에 액세스할 수 있도록 합니다."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"브라우저에 이 비밀번호를 저장하시겠습니까?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"나중에"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"저장"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Wi-Fi에 연결할 수 없습니다"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 인터넷 연결 상태가 좋지 않습니다."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Direct 작업을 시작합니다. 이 작업을 하면 Wi-Fi 클라이언트/핫스팟 작업이 중지됩니다."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct를 시작하지 못했습니다."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 켜짐"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"설정으로 이동하려면 터치하세요."</string>
     <string name="accept" msgid="1645267259272829559">"동의"</string>
     <string name="decline" msgid="2112225451706137894">"거부"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"초대장을 보냈습니다."</string>
diff --git a/core/res/res/values-large/themes.xml b/core/res/res/values-large/themes.xml
index 871a131..448e7c8 100644
--- a/core/res/res/values-large/themes.xml
+++ b/core/res/res/values-large/themes.xml
@@ -33,17 +33,17 @@
  -->
 <resources>
     <style name="Theme.Holo.DialogWhenLarge"
-            parent="@android:style/Theme.Holo.Dialog.MinWidth">
+            parent="@android:style/Theme.Holo.Dialog.FixedSize">
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
     <style name="Theme.Holo.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.Holo.Dialog.NoActionBar.MinWidth">
+            parent="@android:style/Theme.Holo.Dialog.NoActionBar.FixedSize">
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
     <style name="Theme.Holo.Light.DialogWhenLarge"
-            parent="@android:style/Theme.Holo.Light.Dialog.MinWidth">
+            parent="@android:style/Theme.Holo.Light.Dialog.FixedSize">
     </style>
     <style name="Theme.Holo.Light.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.Holo.Light.Dialog.NoActionBar.MinWidth">
+            parent="@android:style/Theme.Holo.Light.Dialog.NoActionBar.FixedSize">
     </style>
 </resources>
diff --git a/core/res/res/values-large/themes_device_defaults.xml b/core/res/res/values-large/themes_device_defaults.xml
index 52fff5c..d57e827 100644
--- a/core/res/res/values-large/themes_device_defaults.xml
+++ b/core/res/res/values-large/themes_device_defaults.xml
@@ -32,17 +32,17 @@
  -->
 <resources>
     <style name="Theme.DeviceDefault.DialogWhenLarge"
-            parent="@android:style/Theme.DeviceDefault.Dialog.MinWidth">
+            parent="@android:style/Theme.DeviceDefault.Dialog.FixedSize">
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
     <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar.MinWidth">
+            parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
         <item name="preferencePanelStyle">@style/PreferencePanel.Dialog</item>
     </style>
     <style name="Theme.DeviceDefault.Light.DialogWhenLarge"
-            parent="@android:style/Theme.DeviceDefault.Light.Dialog.MinWidth">
+            parent="@android:style/Theme.DeviceDefault.Light.Dialog.FixedSize">
     </style>
     <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar"
-            parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth">
+            parent="@android:style/Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
     </style>
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index a1694af..739dca8 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Savininkui leidžiama teikti užklausas patikrinti paketą. Įprastoms programoms to neturėtų prireikti."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"pasiekti nuosekliuosius prievadus"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Leidžiama savininkui pasiekti nuosekliuosius prievadus naudojant „SerialManager“ API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Ar norite, kad naršyklė atsimintų šį slaptažodį?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne dabar"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Atsiminti"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepavyko prisijungti prie „Wi-Fi“"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" turi prastą interneto ryšį."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Tiesioginis „Wi-Fi“ ryšys"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Paleiskite „Wi-Fi Direct“. Bus išjungta „Wi-Fi“ programa / viešosios interneto prieigos taškas."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nepavyko paleisti „Wi-Fi Direct“."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"„Wi-Fi Direct“ įjungta"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Jei norite peržiūrėti nustatymus, palieskite"</string>
     <string name="accept" msgid="1645267259272829559">"Sutikti"</string>
     <string name="decline" msgid="2112225451706137894">"Atmesti"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pakvietimas išsiųstas"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index aeec70b..c36434c 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ļauj īpašniekam sūtīt pakotņu verificētāju pieprasījumus. Parastajām lietotnēm tas nekad nav nepieciešams."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"piekļuve seriālajiem portiem"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Ļauj īpašniekam piekļūt seriālajiem portiem, izmantojot SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Vai vēlaties, lai pārlūkprogrammā tiktu saglabāta šī parole?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne tagad"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Atcerēties"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nevarēja izveidot savienojumu ar Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ir slikts interneta savienojums."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Palaist programmu Wi-Fi Direct. Tādējādi tiks izslēgta Wi-Fi klienta/tīklāja darbība."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nevarēja palaist programmu Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ir ieslēgts"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pieskarieties, lai piekļūtu iestatījumiem."</string>
     <string name="accept" msgid="1645267259272829559">"Piekrist"</string>
     <string name="decline" msgid="2112225451706137894">"Noraidīt"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Ielūgums ir nosūtīts."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0610e88..6d0f5fd 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Membenarkan pemegang membuat permintaan pengesah pakej. Tidak sekali-kali diperlukan untuk apl normal."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"akses port bersiri"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Membenarkan pemegang mengakses port bersiri menggunakan API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Adakah anda mahu penyemak imbas mengingati kata laluan ini?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Bukan sekarang"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Tidak boleh menyambung kepada Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" mempunyai sambungan internet yang kurang baik."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Langsung"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Mulakan Wi-Fi Langsung. Hal ini akan mematikan pengendalian klien/liputan Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Tidak dapat memulakan Wi-Fi Langsung."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct dihidupkan"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Sentuh untuk tetapan"</string>
     <string name="accept" msgid="1645267259272829559">"Terima"</string>
     <string name="decline" msgid="2112225451706137894">"Tolak"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Jemputan dihantar"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e82718e..41ff046 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Lar innehaveren sende forespørsler om pakkeverifikatorer. Skal aldri være nødvendig for normale apper."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"tilgang til serielle porter"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Gir innehaveren tilgang til serielle porter ved hjelp av SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Ønsker du at nettleseren skal huske dette passordet?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ikke nå"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Husk"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan ikke koble til Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dårlig Internett-tilkobling."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Start Wi-Fi Direct. Dette deaktiverer Wi-Fi-klienten/-sonen."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kunne ikke starte Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct er slått på"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Berør for å se innstillinger"</string>
     <string name="accept" msgid="1645267259272829559">"Godta"</string>
     <string name="decline" msgid="2112225451706137894">"Avslå"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitasjonen er sendt"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index ef4dd6a..8e5e8bc 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -764,6 +764,8 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Hiermee kan de houder verzoeken indienen voor pakketcontroles. Nooit vereist voor normale apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"toegang krijgen tot seriële poorten"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"De houder toestaan toegang tot seriële poorten te krijgen met de SerialManager API."</string>
+    <string name="permlab_accessContentProvidersExternally" msgid="5077774297943409285">"externe toegang tot inhoudsproviders"</string>
+    <string name="permdesc_accessContentProvidersExternally" msgid="4544346486697853685">"Hiermee kan de houder toegang krijgen tot inhoudsproviders via de shell. Nooit vereist voor normale apps."</string>
     <string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
@@ -973,6 +975,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" heeft een slechte internetverbinding."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wifi Direct starten. Hierdoor wordt de wifi-client/hotspot uitgeschakeld."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kan Wifi Direct niet starten."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct is actief"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Aanraken voor instellingen"</string>
     <string name="accept" msgid="1645267259272829559">"Accepteren"</string>
     <string name="decline" msgid="2112225451706137894">"Weigeren"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Uitnodiging verzonden"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index f231d89..694ed75 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -216,7 +216,7 @@
     <string name="permlab_removeTasks" msgid="6821513401870377403">"zatrzymywanie uruchomionych aplikacji"</string>
     <string name="permdesc_removeTasks" msgid="1394714352062635493">"Umożliwia aplikacji usuwanie zadań i kończenie powiązanych z nimi aplikacji. Złośliwe aplikacje mogą zakłócić działanie innych aplikacji."</string>
     <string name="permlab_setScreenCompatibility" msgid="6975387118861842061">"ustaw zgodność ekranu"</string>
-    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pozwala aplikacji na sterowanie trybem zgodności ekranu innych aplikacji. Złośliwe aplikacje mogą zmienić zachowanie innych aplikacji."</string>
+    <string name="permdesc_setScreenCompatibility" msgid="692043618693917374">"Pozwala aplikacji na sterowanie trybem zgodności ekranu innych aplikacji. Złośliwe aplikacje mogą zmienić zachowanie innych programów."</string>
     <string name="permlab_setDebugApp" msgid="3022107198686584052">"włączenie debugowania aplikacji"</string>
     <string name="permdesc_setDebugApp" msgid="4474512416299013256">"Pozwala aplikacji na włączenie debugowania innej aplikacji. Złośliwe aplikacje mogą to wykorzystać do kończenia pracy innych programów."</string>
     <string name="permlab_changeConfiguration" msgid="8214475779521218295">"zmienianie ustawień interfejsu użytkownika"</string>
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pozwala na wysyłanie żądań weryfikacji pakietu. To uprawnienie nie powinno być potrzebne zwykłym aplikacjom."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"dostęp do portów szeregowych"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Umożliwia posiadaczowi dostęp do portów szeregowych przy użyciu interfejsu API narzędzia SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Czy chcesz, aby zapamiętać to hasło w przeglądarce?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nie teraz"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamiętaj"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nie można połączyć się z siecią Wi-Fi."</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ma powolne połączenie internetowe."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Uruchom Wi-Fi Direct. Spowoduje to wyłączenie klienta lub punktu dostępu Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Nie można uruchomić Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct włączone"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotknij, aby zmienić ustawienia"</string>
     <string name="accept" msgid="1645267259272829559">"Akceptuj"</string>
     <string name="decline" msgid="2112225451706137894">"Odrzuć"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Wysłano zaproszenie"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index f3f06009..3fa89d3 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite ao titular solicitar verificadores de pacotes. Nunca deverá ser necessário para aplicações normais."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"aceder a portas série"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite ao titular aceder a portas de série através da API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Quer que o browser memorize esta palavra-passe?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível ligar a Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma ligação à internet fraca."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Esta opção desativará o cliente/zona Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"O Wi-Fi Direct está ativado"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Toque para aceder às definições"</string>
     <string name="accept" msgid="1645267259272829559">"Aceitar"</string>
     <string name="decline" msgid="2112225451706137894">"Recusar"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index b49c36b..d99bc60 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite que o titular solicite verificadores de pacote. Nunca deve ser necessário para aplicativos normais."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"acessar portas seriais"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite que o detentor tenha acesso a portas seriais usando a API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Deseja que o navegador lembre desta senha?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Agora não"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Lembrar"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Não foi possível se conectar a redes Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" tem uma conexão de baixa qualidade com a Internet."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Iniciar o Wi-Fi Direct. Isso desativará o ponto de acesso/cliente Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Não foi possível iniciar o Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct ativado"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tocar para acessar configurações"</string>
     <string name="accept" msgid="1645267259272829559">"Aceitar"</string>
     <string name="decline" msgid="2112225451706137894">"Recusar"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Convite enviado"</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index 1447c0e..5b8efa6 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -1155,6 +1155,10 @@
     <skip />
     <!-- no translation found for permdesc_serialPort (2991639985224598193) -->
     <skip />
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Vulais Vus ch\'il navigatur memorisescha quest pled-clav?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Betg ussa"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Memorisar"</string>
@@ -1418,6 +1422,16 @@
     <skip />
     <!-- no translation found for wifi_watchdog_network_disabled_detailed (5548780776418332675) -->
     <skip />
+    <!-- no translation found for wifi_p2p_dialog_title (97611782659324517) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_turnon_message (2909250942299627244) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_failed_message (3763669677935623084) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_enabled_notification_title (2068321881673734886) -->
+    <skip />
+    <!-- no translation found for wifi_p2p_enabled_notification_message (1638949953993894335) -->
+    <skip />
     <!-- no translation found for accept (1645267259272829559) -->
     <skip />
     <!-- no translation found for decline (2112225451706137894) -->
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f241e8e..d870d58 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Permite proprietarului să efectueze solicitări pentru verificatori de pachete. Nu ar trebui să fie niciodată necesară pentru aplicaţiile obişnuite."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"acces la porturi seriale"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Permite posesorului accesul la porturile serial utilizând API-ul SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Doriţi ca browserul să reţină această parolă?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Nu acum"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Reţineţi"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nu se poate conecta la Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" are o conexiune la internet slabă."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Porniţi Wi-Fi Direct. Acest lucru va dezactiva clientul/hotspotul Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct nu a putut porni."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct este activat"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Atingeţi pentru setări"</string>
     <string name="accept" msgid="1645267259272829559">"Acceptaţi"</string>
     <string name="decline" msgid="2112225451706137894">"Refuzaţi"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Invitaţia a fost trimisă."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 809da83..0b63de1 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Приложение сможет запрашивать проверку пакетов. Это разрешение не используется обычными приложениями."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"доступ к последовательным портам"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Открыть владельцу доступ к последовательным портам с помощью SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Вы хотите, чтобы браузер запомнил этот пароль?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не сейчас"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запомнить"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не удалось подключиться к сети Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" – плохое интернет-соединение."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Начать соединение через Wi-Fi Direct. Модуль Wi-Fi будет отключен."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не удалось запустить Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct включен"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Нажмите, чтобы открыть настройки"</string>
     <string name="accept" msgid="1645267259272829559">"Принять"</string>
     <string name="decline" msgid="2112225451706137894">"Отклонить"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Приглашение отправлено"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 7d75949..df25ac7 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Umožňuje držiteľovi podávať žiadosti o overenie balíkov. Bežné aplikácie by toto nastavenie nemali nikdy potrebovať."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"prístup k sériovým portom"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Držiteľa oprávňuje na prístup k sériovým portom pomocou rozhrania API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Chcete, aby si prehliadač zapamätal toto heslo?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Teraz nie"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapamätať"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Nepodarilo sa pripojiť k sieti Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" má nekvalitné internetové pripojenie."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Priame pripojenie Wi-Fi"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Spustiť priame pripojenie siete Wi-Fi. Táto možnosť vypne sieť Wi-Fi v režime klient alebo hotspot."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Priame pripojenie siete Wi-Fi sa nepodarilo spustiť"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Priame pripojenie siete Wi-Fi je zapnuté"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Nastavenia otvoríte dotykom"</string>
     <string name="accept" msgid="1645267259272829559">"Prijať"</string>
     <string name="decline" msgid="2112225451706137894">"Odmietnuť"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Pozvánka bola odoslaná"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index e152a2f..88d02ab 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Imetniku omogoča zahtevanje preverjanja paketov. Tega nikoli ni treba uporabiti za navadne programe."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"dostop do serijskih vrat"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Imetniku omogoča, da z API-jem za SerialManager dostopa do serijskih vrat."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Ali želite, da si brskalnik zapomni to geslo?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Ne zdaj"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Zapomni si"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Z omrežjem Wi-Fi se ni mogoče povezati"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ima slabo internetno povezavo."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Zaženite Wi-Fi Direct. S tem boste izklopili odjemalca/dostopno točko Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string>
     <string name="accept" msgid="1645267259272829559">"Sprejmi"</string>
     <string name="decline" msgid="2112225451706137894">"Zavrni"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Povabilo je poslano"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 7f1dbcd..7d0b9f5 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Омогућава да власник упућује захтеве верификаторима пакета. Уобичајене апликације никада не би требало да је користе."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"приступ серијским портовима"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Омогућава власнику да приступи серијским портовима помоћу SerialManager API-ја."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Желите ли да прегледач запамти ову лозинку?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не сада"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запамти"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Није било могуће повезати са Wi-Fi мрежом"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" има лошу интернет везу."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Покрените Wi-Fi Direct. Тиме ћете искључити клијента/хотспот за Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Није могуће покренути Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct је укључен"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Додирните за подешавања"</string>
     <string name="accept" msgid="1645267259272829559">"Прихвати"</string>
     <string name="decline" msgid="2112225451706137894">"Одбиј"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Позивница је послата"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 10ecffc..ee6295f 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Tillåter att innehavaren skickar förfrågningar till paketverifierare. Det ska inte behövas för vanliga appar."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"åtkomst till serieportar"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Innebär att innehavaren får åtkomst till serieportar med programmeringsgränssnittet för SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Vill du att webbläsaren ska komma ihåg lösenordet?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Inte nu"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Kom ihåg"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Det gick inte att ansluta till Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" har en dålig Internetanslutning."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi direkt"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Starta direkt Wi-Fi-användning. Detta inaktiverar Wi-Fi-användning med klient/trådlös surfzon."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Det gick inte att starta Wi-Fi direkt."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct är aktiverat"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Tryck om du vill visa inställningar"</string>
     <string name="accept" msgid="1645267259272829559">"Godkänn"</string>
     <string name="decline" msgid="2112225451706137894">"Avvisa"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Inbjudan har skickats"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d245685..70b7c2e 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Inaruhusu mmiliki kutuma maombi ya vibainishi furushi. Kamwe hazitahitajika kwa programu za kawaida."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"kituo tambulishi cha ufikivu"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Inaruhusu mmiliki kufikia vituo tambulishi kwa kutumia KisimamiziTambulishi cha API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Unataka kuvinjari ili ukumbuke nenosiri hili?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Si Sasa"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Haikuweza kuunganisha kwa Mtandao-Hewa"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ina muunganisho duni wa Mtandao."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Mtandao hewa Moja kwa moja"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Anzisha Wi-Fi Moja kwa Moja. Hii itazima mteja/mtandao-hewa wa Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Haikuweza kuanzisha Wi-Fi Moja kwa Moja."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi ya Moja kwa Moja imewashwa"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Gusa kwa ajili ya mipangilio"</string>
     <string name="accept" msgid="1645267259272829559">"Kubali"</string>
     <string name="decline" msgid="2112225451706137894">"Kataa"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Mwaliko umetumwa"</string>
diff --git a/core/res/res/values-sw600dp/dimens.xml b/core/res/res/values-sw600dp/dimens.xml
index 431a502..13acdd6 100644
--- a/core/res/res/values-sw600dp/dimens.xml
+++ b/core/res/res/values-sw600dp/dimens.xml
@@ -68,5 +68,19 @@
 
     <!-- Minimum width for an action button in the menu area of an action bar -->
     <dimen name="action_button_min_width">64dip</dimen>
+
+    <!-- The platform's desired fixed width for a dialog along the major axis
+         (the screen is in landscape). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_width_major">50%</item>
+    <!-- The platform's desired fixed width for a dialog along the minor axis
+         (the screen is in portrait). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_width_minor">70%</item>
+    <!-- The platform's desired fixed height for a dialog along the major axis
+         (the screen is in portrait). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_height_major">60%</item>
+    <!-- The platform's desired fixed height for a dialog along the minor axis
+         (the screen is in landscape). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_height_minor">90%</item>
+
 </resources>
 
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 97f1c70..0acd104 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"อนุญาตให้ผู้ใช้ส่งคำขอให้มีการยืนยันแพคเกจ ไม่ควรต้องใช้สำหรับแอปพลิเคชันทั่วไป"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"เข้าถึงพอร์ตอนุกรม"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"อนุญาตให้ผู้ถือสามารถเข้าถึงพอร์ตอนุกรมโดยใช้ SerialManager API"</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"คุณต้องการให้เบราว์เซอร์จำรหัสผ่านนี้หรือไม่"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"ยังไม่ใช้งานขณะนี้"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"จำไว้"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"ไม่สามารถเชื่อมต่อ Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" มีสัญญาณอินเทอร์เน็ตไม่ดี"</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"เริ่มการทำงาน WiFi Direct ซึ่งจะเป็นการปิดการทำงาน WiFi ไคลเอ็นต์/ฮอตสปอต"</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"ไม่สามารถเริ่ม WiFi Direct ได้"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"เปิด Wi-Fi Direct อยู่"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"แตะเพื่อตั้งค่า"</string>
     <string name="accept" msgid="1645267259272829559">"ยอมรับ"</string>
     <string name="decline" msgid="2112225451706137894">"ปฏิเสธ"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"ส่งข้อความเชิญแล้ว"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index f59cde4..3bde5c8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Pinapayagan ang may-ari na gumawa ng mga kahilingan ng mga taga-verify ng package. Hindi kailanman dapat na kailanganin para sa normal na apps."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"mag-access sa mga serial port"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Binibigyang-daan ang may-ari na mag-access ng mga serial port gamit ang SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Gusto mo bang tandaan ng browser ang password na ito?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Hindi ngayon"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Tandaan"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Hindi makakonekta sa Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" ay mayroong mahinang koneksyon sa Internet."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Simulan ang Wi-Fi Direct. I-o-off nito ang client/hotspot ng Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Hindi masimulan ang Wi-Fi Direct"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Ang Wi-Fi Direct ay naka-on"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Pindutin para sa mga setting"</string>
     <string name="accept" msgid="1645267259272829559">"Tanggapin"</string>
     <string name="decline" msgid="2112225451706137894">"Tanggihan"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Naipadala ang imbitasyon"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index bcaa9a8..1b27dbd 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cihazın sahibine, paket doğrulayıcıları için istek yapma izni verir. Normal uygulamalar için gerekli olmaz."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"seri bağlantı noktalarına eriş"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"İzin sahibinin, SerialManager API\'sını kullanarak seri bağlantı noktalarına erişmesine olanak sağlar."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Tarayıcının bu şifreyi anımsamasını istiyor musunuz?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Şimdi değil"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Anımsa"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kablosuz bağlantısı kurulamadı"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" İnternet bağlantısı zayıf."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Kablosuz Doğrudan Bağlantı"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Kablosuz Doğrudan Bağlantıyı başlat. Bu işlem, Kablosuz istemci/hotspot kullanımını kapatacak."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Kablosuz Doğrudan bağlantı başlatılamadı."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Kablosuz Doğrudan özelliği açık"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Ayarlar için dokunun"</string>
     <string name="accept" msgid="1645267259272829559">"Kabul et"</string>
     <string name="decline" msgid="2112225451706137894">"Reddet"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Davetiye gönderildi"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6288aa1..eb22ec8 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Дозволяє власникові робити запити на програми перевірки пакетів. Ніколи не застосовується для звичайних програм."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"отримувати доступ до послідовних портів"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Дозволяє власнику отримувати доступ до послідовних портів за допомогою API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Хочете, щоб переглядач запам\'ятав цей пароль?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Не зараз"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Запам\'ятати"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Не вдалося під’єднатися до мережі Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" має погане з’єднання з Інтернетом."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Запустити Wi-Fi Direct. Це вимкне з’єднання Wi-Fi клієнт/точка доступу."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Не вдалося запустити Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct увімкнено"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Торкніться, щоб побачити налаштування"</string>
     <string name="accept" msgid="1645267259272829559">"Прийняти"</string>
     <string name="decline" msgid="2112225451706137894">"Відхилити"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Запрошення надіслано"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index ba81838..583d216 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Cho phép chủ sở hữu yêu cầu trình xác minh gói. Không cần thiết cho các ứng dụng thông thường."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"truy cập cổng nối tiếp"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Cho phép chủ sở hữu truy cập cổng nối tiếp sử dụng API SerialManager."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Bạn có muốn trình duyệt nhớ mật khẩu này không?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Không phải bây giờ"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Nhớ"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Không thể kết nối với Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" có kết nối Internet không tốt."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Khởi động Wi-Fi Direct. Việc này sẽ tắt hoạt động của ứng dụng khách/điểm phát sóng Wi-Fi."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Không thể khởi động Wi-Fi Direct."</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct được bật"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Chạm để cài đặt"</string>
     <string name="accept" msgid="1645267259272829559">"Đồng ý"</string>
     <string name="decline" msgid="2112225451706137894">"Từ chối"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Đã gửi thư mời"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index cbfc222..ca3c65c 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允许用户请求使用程序包验证程序。普通应用程序绝不需要此权限。"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"访问串行端口"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"允许持有人使用 SerialManager API 访问串行端口。"</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"是否希望浏览器记住此密码?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"暂不保存"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"记住"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"无法连接到 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 互联网连接状况不佳。"</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"启动 Wi-Fi Direct。此操作将会关闭 Wi-Fi 客户端/热点。"</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"无法启动 Wi-Fi Direct。"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"已启用 Wi-Fi Direct"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"通过触摸进行设置"</string>
     <string name="accept" msgid="1645267259272829559">"接受"</string>
     <string name="decline" msgid="2112225451706137894">"拒绝"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀请已发送"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 4d6042c..9b11c43 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"允許應用程式要求驗證套件 (一般應用程式不需使用)。"</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"存取序列埠"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"允許應用程式使用 SerialManager API 存取序列埠。"</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"是否記住此密碼?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"現在不要"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"記住"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"無法連線至 Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" 的網際網路連線狀況不佳。"</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"啟動 WiFi Direct 作業,這會關閉 WiFi 用戶端/無線基地台作業。"</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"無法啟動 WiFi Direct。"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct 已開啟"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"輕觸即可設定"</string>
     <string name="accept" msgid="1645267259272829559">"接受"</string>
     <string name="decline" msgid="2112225451706137894">"拒絕"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"邀請函已傳送"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index c90fe76..8d02eff 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -764,6 +764,10 @@
     <string name="permdesc_bindPackageVerifier" msgid="3180741773233862126">"Ivumela umnikazi ukuthi enze izicelo zezinsiza eziqinisekisa iphakheji. Akumele kudingeke ekusetshenzisweni okujwayelekile."</string>
     <string name="permlab_serialPort" msgid="546083327654631076">"finyelela kuma- serial port"</string>
     <string name="permdesc_serialPort" msgid="2991639985224598193">"Ivumela umnikai ukuthi athole inombolo ye-serial ukue angene kwiindawo ze-serial esebenzisa i-SerialManager API."</string>
+    <!-- no translation found for permlab_accessContentProvidersExternally (5077774297943409285) -->
+    <skip />
+    <!-- no translation found for permdesc_accessContentProvidersExternally (4544346486697853685) -->
+    <skip />
     <string name="save_password_message" msgid="767344687139195790">"Ingabe ufuna ukuba isiphequluli sikhumbule lephasiwedi?"</string>
     <string name="save_password_notnow" msgid="6389675316706699758">"Hha yi manje"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"Khumbula"</string>
@@ -973,6 +977,11 @@
     <skip />
     <string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Ayikwazanga ukuxhuma kwi-Wi-Fi"</string>
     <string name="wifi_watchdog_network_disabled_detailed" msgid="5548780776418332675">" inoxhumano oluphansi lwe-inthanethi."</string>
+    <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"I-WiFi Eqondile"</string>
+    <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Qala ukusebenza kwe-WiFi Okuqondile. Lokhu kuzocima ikhasimende le-WiFi/Ukusebenza okwe-hotspot"</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Yehlulekile ukuqala i-Wi-Fi Ngqo"</string>
+    <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"I-Wi-Fi Direct ivulekile"</string>
+    <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Thinta ukuze uthole izilungiselelo"</string>
     <string name="accept" msgid="1645267259272829559">"Yamukela"</string>
     <string name="decline" msgid="2112225451706137894">"Nqaba"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Isimemo sithunyelwe"</string>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 16b7ff3..c152b73 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1556,6 +1556,24 @@
              an absolute dimension or a fraction of the screen size in that
              dimension. -->
         <attr name="windowMinWidthMinor" format="dimension|fraction" />
+
+        <!-- A fixed width for the window along the major axis of the screen,
+             that is, when in landscape. Can be either an absolute dimension
+             or a fraction of the screen size in that dimension. -->
+        <attr name="windowFixedWidthMajor" format="dimension|fraction" />
+        <!-- A fixed height for the window along the minor axis of the screen,
+             that is, when in landscape. Can be either an absolute dimension
+             or a fraction of the screen size in that dimension. -->
+        <attr name="windowFixedHeightMinor" format="dimension|fraction" />
+
+        <!-- A fixed width for the window along the minor axis of the screen,
+             that is, when in portrait. Can be either an absolute dimension
+             or a fraction of the screen size in that dimension. -->
+        <attr name="windowFixedWidthMinor" format="dimension|fraction" />
+        <!-- A fixed height for the window along the major axis of the screen,
+             that is, when in portrait. Can be either an absolute dimension
+             or a fraction of the screen size in that dimension. -->
+        <attr name="windowFixedHeightMajor" format="dimension|fraction" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 82ef68a..6d6b86b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -108,6 +108,20 @@
          is along the major axis (that is the screen is landscape).  This may
          be either a fraction or a dimension. -->
     <item type="dimen" name="dialog_min_width_major">65%</item>
+
+    <!-- The platform's desired fixed width for a dialog along the major axis
+         (the screen is in landscape). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_width_major">320dp</item>
+    <!-- The platform's desired fixed width for a dialog along the minor axis
+         (the screen is in portrait). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_width_minor">320dp</item>
+    <!-- The platform's desired fixed height for a dialog along the major axis
+         (the screen is in portrait). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_height_major">80%</item>
+    <!-- The platform's desired fixed height for a dialog along the minor axis
+         (the screen is in landscape). This may be either a fraction or a dimension.-->
+    <item type="dimen" name="dialog_fixed_height_minor">100%</item>
+
     <!-- Preference activity, vertical padding for the header list -->
     <dimen name="preference_screen_header_vertical_padding">0dp</dimen>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f347a4e..2a6cef3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -212,6 +212,10 @@
   <java-symbol type="attr" name="textAppearanceMisspelledSuggestion" />
   <java-symbol type="attr" name="textColorSearchUrl" />
   <java-symbol type="attr" name="timePickerStyle" />
+  <java-symbol type="attr" name="windowFixedWidthMajor" />
+  <java-symbol type="attr" name="windowFixedWidthMinor" />
+  <java-symbol type="attr" name="windowFixedHeightMajor" />
+  <java-symbol type="attr" name="windowFixedHeightMinor" />
 
   <java-symbol type="bool" name="action_bar_embed_tabs" />
   <java-symbol type="bool" name="action_bar_expanded_action_views_exclusive" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 7111d00..3c1f50d 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2248,6 +2248,14 @@
     <!-- Description of an application permission which allows the application access serial ports via the SerialManager. [CHAR LIMIT=NONE] -->
     <string name="permdesc_serialPort">Allows the holder to access serial ports using the SerialManager API.</string>
 
+    <!-- Title of an application permission which allows the holder to access content
+         providers from outside an ApplicationThread. [CHAR LIMIT=40] -->
+    <string name="permlab_accessContentProvidersExternally">access content providers externally</string>
+    <!-- Description of an application permission which allows the holder to access
+         content providers from outside an ApplicationThread. [CHAR LIMIT=NONE] -->
+    <string name="permdesc_accessContentProvidersExternally">Allows the holder to access content
+     providers from the shell. Should never be needed for normal apps.</string>
+
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Text in the save password dialog, asking if the browser should remember a password. -->
     <string name="save_password_message">Do you want the browser to remember this password?</string>
     <!-- If the user enters a password in a form on a website, a dialog will come up asking if they want to save the password. Button in the save password dialog, saying not to remember this password. -->
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 7046fc5..55438b2 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -1580,6 +1580,22 @@
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
+    <!-- Variant of Theme.Holo.Dialog that has a fixed size. -->
+    <style name="Theme.Holo.Dialog.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- Variant of Theme.Holo.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.Holo.Dialog.NoActionBar.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
     <!-- Variant of Theme.Holo.Dialog that does not include a frame (or background).
          The view hierarchy of the dialog is responsible for drawing all of
          its pixels. -->
@@ -1672,6 +1688,22 @@
         <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
     </style>
 
+    <!-- Variant of Theme.Holo.Light.Dialog that has a fixed size. -->
+    <style name="Theme.Holo.Light.Dialog.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- Variant of Theme.Holo.Light.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.Holo.Light.Dialog.NoActionBar.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
     <!-- Theme for a window that will be displayed either full-screen on
          smaller screens (small, normal) or as a dialog on larger screens
          (large, xlarge). -->
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index abe4aad..7fd981c 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -379,6 +379,23 @@
     <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Dialog.NoActionBar.MinWidth" >
 
     </style>
+
+    <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Dialog.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
     floating (not fill the entire screen), and puts a frame around its contents. You can set this
     theme on an activity if you would like to make an activity that looks like a Dialog.-->
@@ -406,6 +423,23 @@
     <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Holo.Light.Dialog.NoActionBar.MinWidth" >
 
     </style>
+
+    <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Light.Dialog.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
+    <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.FixedSize">
+        <item name="windowFixedWidthMajor">@android:dimen/dialog_fixed_width_major</item>
+        <item name="windowFixedWidthMinor">@android:dimen/dialog_fixed_width_minor</item>
+        <item name="windowFixedHeightMajor">@android:dimen/dialog_fixed_height_major</item>
+        <item name="windowFixedHeightMinor">@android:dimen/dialog_fixed_height_minor</item>
+    </style>
+
     <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
     screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
     <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Holo.DialogWhenLarge" >
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
index 9819c54..9c1922f 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestRunner.java
@@ -46,8 +46,7 @@
             // create a new test suite
             suite.setName("ConnectivityManagerWifiOnlyFunctionalTests");
             String[] methodNames = {"testConnectToWifi", "testConnectToWifWithKnownAP",
-                    "testDisconnectWifi", "testDataConnectionOverAMWithWifi",
-                    "testDataConnectionWithWifiToAMToWifi", "testWifiStateChange"};
+                    "testDisconnectWifi", "testWifiStateChange"};
             Class<ConnectivityManagerMobileTest> testClass = ConnectivityManagerMobileTest.class;
             for (String method: methodNames) {
                 suite.addTest(TestSuite.createTest(testClass, method));
diff --git a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
index 2fb4237..3dc140b 100644
--- a/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
+++ b/core/tests/coretests/src/android/accessibilityservice/InterrogationActivityTest.java
@@ -50,6 +50,12 @@
     // Timeout for the accessibility state of an Activity to be fully initialized.
     private static final int TIMEOUT_PROPAGATE_ACCESSIBILITY_EVENT_MILLIS = 5000;
 
+    // Timeout for which non getting accessibility events considers the app idle.
+    private static final long IDLE_EVENT_TIME_DELTA_MILLIS = 200;
+
+    // Timeout in which to wait for idle device.
+    private static final long GLOBAL_IDLE_DETECTION_TIMEOUT_MILLIS = 1000;
+
     // Handle to a connection to the AccessibilityManagerService
     private UiTestAutomationBridge mUiTestAutomationBridge;
 
@@ -62,6 +68,8 @@
         super.setUp();
         mUiTestAutomationBridge = new UiTestAutomationBridge();
         mUiTestAutomationBridge.connect();
+        mUiTestAutomationBridge.waitForIdle(IDLE_EVENT_TIME_DELTA_MILLIS,
+                GLOBAL_IDLE_DETECTION_TIMEOUT_MILLIS);
         mUiTestAutomationBridge.executeCommandAndWaitForAccessibilityEvent(new Runnable() {
                 // wait for the first accessibility event
                 @Override
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 6cd07a3..8be1db2 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -158,6 +158,7 @@
     <assign-permission name="android.permission.BACKUP" uid="shell" />
     <assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" />
     <assign-permission name="android.permission.STOP_APP_SWITCHES" uid="shell" />
+    <assign-permission name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" uid="shell" />
 
     <assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
     <assign-permission name="android.permission.ACCESS_DRM" uid="media" />
diff --git a/data/fonts/DroidNaskh-Bold.ttf b/data/fonts/DroidNaskh-Bold.ttf
index 6b7d4f0..692b796 100644
--- a/data/fonts/DroidNaskh-Bold.ttf
+++ b/data/fonts/DroidNaskh-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidNaskh-Regular.ttf b/data/fonts/DroidNaskh-Regular.ttf
index d11e1ae..da9a45f 100644
--- a/data/fonts/DroidNaskh-Regular.ttf
+++ b/data/fonts/DroidNaskh-Regular.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
index 2379b2d..cfbc66a 100644
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallbackFull.ttf b/data/fonts/DroidSansFallbackFull.ttf
index 41b015d..0cacabe 100644
--- a/data/fonts/DroidSansFallbackFull.ttf
+++ b/data/fonts/DroidSansFallbackFull.ttf
Binary files differ
diff --git a/drm/java/android/drm/DrmInfo.java b/drm/java/android/drm/DrmInfo.java
index 8812bfe..22d06c7 100755
--- a/drm/java/android/drm/DrmInfo.java
+++ b/drm/java/android/drm/DrmInfo.java
@@ -49,6 +49,13 @@
         mInfoType = infoType;
         mMimeType = mimeType;
         mData = data;
+        if (!isValid()) {
+            final String msg = "infoType: " + infoType + "," +
+                               "mimeType: " + mimeType + "," +
+                               "data: " + data;
+
+            throw new IllegalArgumentException(msg);
+        }
     }
 
     /**
@@ -69,6 +76,13 @@
             // call would fail with IllegalArgumentException because of mData = null
             mData = null;
         }
+        if (!isValid()) {
+            final String msg = "infoType: " + infoType + "," +
+                               "mimeType: " + mimeType + "," +
+                               "data: " + mData;
+
+            throw new IllegalArgumentException();
+        }
     }
 
     /**
diff --git a/drm/java/android/drm/DrmInfoRequest.java b/drm/java/android/drm/DrmInfoRequest.java
index 1429fa5..621da41 100755
--- a/drm/java/android/drm/DrmInfoRequest.java
+++ b/drm/java/android/drm/DrmInfoRequest.java
@@ -67,6 +67,11 @@
     public DrmInfoRequest(int infoType, String mimeType) {
         mInfoType = infoType;
         mMimeType = mimeType;
+        if (!isValid()) {
+            final String msg = "infoType: " + infoType + "," +
+                               "mimeType: " + mimeType;
+            throw new IllegalArgumentException(msg);
+        }
     }
 
     /**
diff --git a/drm/java/android/drm/DrmInfoStatus.java b/drm/java/android/drm/DrmInfoStatus.java
index 5c12ae3..2fe0a78 100755
--- a/drm/java/android/drm/DrmInfoStatus.java
+++ b/drm/java/android/drm/DrmInfoStatus.java
@@ -56,6 +56,10 @@
      * @param _mimeType The MIME type.
      */
     public DrmInfoStatus(int _statusCode, int _infoType, ProcessedData _data, String _mimeType) {
+        if (!DrmInfoRequest.isValidType(_infoType)) {
+            throw new IllegalArgumentException("infoType: " + _infoType);
+        }
+
         statusCode = _statusCode;
         infoType = _infoType;
         data = _data;
diff --git a/drm/java/android/drm/DrmRights.java b/drm/java/android/drm/DrmRights.java
index ef9c21d..d4afed1 100755
--- a/drm/java/android/drm/DrmRights.java
+++ b/drm/java/android/drm/DrmRights.java
@@ -103,6 +103,11 @@
         }
 
         mMimeType = mimeType;
+        if (!isValid()) {
+            final String msg = "mimeType: " + mMimeType + "," +
+                               "data: " + mData;
+            throw new IllegalArgumentException(msg);
+        }
     }
 
     /**
@@ -117,17 +122,25 @@
             mData = data.getData();
 
             String accountId = data.getAccountId();
-            if (null != accountId && !accountId.equals("")) {
-                mAccountId = accountId;
+            if (null == accountId || !accountId.equals("")) {
+                throw new IllegalArgumentException("accountId: " + accountId);
             }
+            mAccountId = accountId;
 
             String subscriptionId = data.getSubscriptionId();
-            if (null != subscriptionId && !subscriptionId.equals("")) {
-                mSubscriptionId = subscriptionId;
+            if (null == subscriptionId || !subscriptionId.equals("")) {
+                throw new IllegalArgumentException(
+                            "subscriptionId: " + subscriptionId);
             }
+            mSubscriptionId = subscriptionId;
         }
 
         mMimeType = mimeType;
+        if (!isValid()) {
+            final String msg = "mimeType: " + mMimeType + "," +
+                               "data: " + mData;
+            throw new IllegalArgumentException(msg);
+        }
     }
 
     /**
diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java
index 3f769ee..4d60ac8 100644
--- a/graphics/java/android/renderscript/Program.java
+++ b/graphics/java/android/renderscript/Program.java
@@ -69,6 +69,7 @@
     Element mOutputs[];
     Type mConstants[];
     TextureType mTextures[];
+    String mTextureNames[];
     int mTextureCount;
     String mShader;
 
@@ -111,6 +112,16 @@
     }
 
     /**
+     * @hide
+     */
+    public String getTextureName(int slot) {
+        if ((slot < 0) || (slot >= mTextureCount)) {
+            throw new IllegalArgumentException("Slot ID out of range.");
+        }
+        return mTextureNames[slot];
+    }
+
+    /**
      * Binds a constant buffer to be used as uniform inputs to the
      * program
      *
@@ -180,6 +191,7 @@
         Type mConstants[];
         Type mTextures[];
         TextureType mTextureTypes[];
+        String mTextureNames[];
         int mInputCount;
         int mOutputCount;
         int mConstantCount;
@@ -197,6 +209,7 @@
             mConstantCount = 0;
             mTextureCount = 0;
             mTextureTypes = new TextureType[MAX_TEXTURE];
+            mTextureNames = new String[MAX_TEXTURE];
         }
 
         /**
@@ -300,10 +313,28 @@
          * @return  self
          */
         public BaseProgramBuilder addTexture(TextureType texType) throws IllegalArgumentException {
+            addTexture(texType, "Tex" + mTextureCount);
+            return this;
+        }
+
+        /**
+         * @hide
+         * Adds a texture input to the Program
+         *
+         * @param texType describes that the texture to append it (2D,
+         *                Cubemap, etc.)
+         * @param texName what the texture should be called in the
+         *                shader
+         * @return  self
+         */
+        public BaseProgramBuilder addTexture(TextureType texType, String texName)
+            throws IllegalArgumentException {
             if(mTextureCount >= MAX_TEXTURE) {
                 throw new IllegalArgumentException("Max texture count exceeded.");
             }
-            mTextureTypes[mTextureCount ++] = texType;
+            mTextureTypes[mTextureCount] = texType;
+            mTextureNames[mTextureCount] = texName;
+            mTextureCount ++;
             return this;
         }
 
@@ -317,6 +348,8 @@
             p.mTextureCount = mTextureCount;
             p.mTextures = new TextureType[mTextureCount];
             System.arraycopy(mTextureTypes, 0, p.mTextures, 0, mTextureCount);
+            p.mTextureNames = new String[mTextureCount];
+            System.arraycopy(mTextureNames, 0, p.mTextureNames, 0, mTextureCount);
         }
     }
 
diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java
index 21bace8..ebc15e5 100644
--- a/graphics/java/android/renderscript/ProgramFragment.java
+++ b/graphics/java/android/renderscript/ProgramFragment.java
@@ -59,6 +59,7 @@
         public ProgramFragment create() {
             mRS.validate();
             int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
@@ -76,9 +77,10 @@
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
                 tmp[idx++] = mTextureTypes[i].mID;
+                texNames[i] = mTextureNames[i];
             }
 
-            int id = mRS.nProgramFragmentCreate(mShader, tmp);
+            int id = mRS.nProgramFragmentCreate(mShader, texNames, tmp);
             ProgramFragment pf = new ProgramFragment(id, mRS);
             initProgram(pf);
             return pf;
diff --git a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
index 0ab73c1..cd31db3 100644
--- a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java
@@ -47,6 +47,7 @@
         public ProgramFragmentFixedFunction create() {
             mRS.validate();
             int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
@@ -64,9 +65,10 @@
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
                 tmp[idx++] = mTextureTypes[i].mID;
+                texNames[i] = mTextureNames[i];
             }
 
-            int id = mRS.nProgramFragmentCreate(mShader, tmp);
+            int id = mRS.nProgramFragmentCreate(mShader, texNames, tmp);
             ProgramFragmentFixedFunction pf = new ProgramFragmentFixedFunction(id, mRS);
             initProgram(pf);
             return pf;
diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java
index b3c1bd9..a6cd15b 100644
--- a/graphics/java/android/renderscript/ProgramVertex.java
+++ b/graphics/java/android/renderscript/ProgramVertex.java
@@ -116,6 +116,7 @@
         public ProgramVertex create() {
             mRS.validate();
             int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
@@ -133,9 +134,10 @@
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
                 tmp[idx++] = mTextureTypes[i].mID;
+                texNames[i] = mTextureNames[i];
             }
 
-            int id = mRS.nProgramVertexCreate(mShader, tmp);
+            int id = mRS.nProgramVertexCreate(mShader, texNames, tmp);
             ProgramVertex pv = new ProgramVertex(id, mRS);
             initProgram(pv);
             return pv;
diff --git a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
index 740d6a5..9a43943 100644
--- a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -70,6 +70,7 @@
         public ProgramVertexFixedFunction create() {
             mRS.validate();
             int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2];
+            String[] texNames = new String[mTextureCount];
             int idx = 0;
 
             for (int i=0; i < mInputCount; i++) {
@@ -87,9 +88,10 @@
             for (int i=0; i < mTextureCount; i++) {
                 tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID;
                 tmp[idx++] = mTextureTypes[i].mID;
+                texNames[i] = mTextureNames[i];
             }
 
-            int id = mRS.nProgramVertexCreate(mShader, tmp);
+            int id = mRS.nProgramVertexCreate(mShader, texNames, tmp);
             ProgramVertexFixedFunction pv = new ProgramVertexFixedFunction(id, mRS);
             initProgram(pv);
             return pv;
diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java
index 56303f7..9517513 100644
--- a/graphics/java/android/renderscript/RenderScript.java
+++ b/graphics/java/android/renderscript/RenderScript.java
@@ -569,15 +569,15 @@
         validate();
         rsnProgramBindSampler(mContext, vpf, slot, s);
     }
-    native int  rsnProgramFragmentCreate(int con, String shader, int[] params);
-    synchronized int nProgramFragmentCreate(String shader, int[] params) {
+    native int  rsnProgramFragmentCreate(int con, String shader, String[] texNames, int[] params);
+    synchronized int nProgramFragmentCreate(String shader, String[] texNames, int[] params) {
         validate();
-        return rsnProgramFragmentCreate(mContext, shader, params);
+        return rsnProgramFragmentCreate(mContext, shader, texNames, params);
     }
-    native int  rsnProgramVertexCreate(int con, String shader, int[] params);
-    synchronized int nProgramVertexCreate(String shader, int[] params) {
+    native int  rsnProgramVertexCreate(int con, String shader, String[] texNames, int[] params);
+    synchronized int nProgramVertexCreate(String shader, String[] texNames, int[] params) {
         validate();
-        return rsnProgramVertexCreate(mContext, shader, params);
+        return rsnProgramVertexCreate(mContext, shader, texNames, params);
     }
 
     native int  rsnMeshCreate(int con, int[] vtx, int[] idx, int[] prim);
diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk
index 652189f..ca69e1e 100644
--- a/graphics/jni/Android.mk
+++ b/graphics/jni/Android.mk
@@ -6,6 +6,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
         libandroid_runtime \
+        libandroidfw \
         libnativehelper \
         libRS \
         libcutils \
diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp
index 4d087b0..27ea8f6 100644
--- a/graphics/jni/android_renderscript_RenderScript.cpp
+++ b/graphics/jni/android_renderscript_RenderScript.cpp
@@ -31,9 +31,9 @@
 #include <core/SkTemplates.h>
 #include <images/SkImageDecoder.h>
 
-#include <utils/Asset.h>
-#include <utils/AssetManager.h>
-#include <utils/ResourceTypes.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
 
 #include "jni.h"
 #include "JNIHelp.h"
@@ -41,8 +41,8 @@
 #include "android_runtime/android_view_Surface.h"
 #include "android_runtime/android_util_AssetManager.h"
 
-#include <RenderScript.h>
-#include <RenderScriptEnv.h>
+#include <rs.h>
+#include <rsEnv.h>
 #include <gui/SurfaceTexture.h>
 #include <gui/SurfaceTextureClient.h>
 #include <android_runtime/android_graphics_SurfaceTexture.h>
@@ -54,13 +54,11 @@
 
 class AutoJavaStringToUTF8 {
 public:
-    AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str)
-    {
+    AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) {
         fCStr = env->GetStringUTFChars(str, NULL);
         fLength = env->GetStringUTFLength(str);
     }
-    ~AutoJavaStringToUTF8()
-    {
+    ~AutoJavaStringToUTF8() {
         fEnv->ReleaseStringUTFChars(fJStr, fCStr);
     }
     const char* c_str() const { return fCStr; }
@@ -73,6 +71,42 @@
     jsize       fLength;
 };
 
+class AutoJavaStringArrayToUTF8 {
+public:
+    AutoJavaStringArrayToUTF8(JNIEnv* env, jobjectArray strings, jsize stringsLength)
+    : mEnv(env), mStrings(strings), mStringsLength(stringsLength) {
+        mCStrings = NULL;
+        mSizeArray = NULL;
+        if (stringsLength > 0) {
+            mCStrings = (const char **)calloc(stringsLength, sizeof(char *));
+            mSizeArray = (size_t*)calloc(stringsLength, sizeof(size_t));
+            for (jsize ct = 0; ct < stringsLength; ct ++) {
+                jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
+                mCStrings[ct] = mEnv->GetStringUTFChars(s, NULL);
+                mSizeArray[ct] = mEnv->GetStringUTFLength(s);
+            }
+        }
+    }
+    ~AutoJavaStringArrayToUTF8() {
+        for (jsize ct=0; ct < mStringsLength; ct++) {
+            jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
+            mEnv->ReleaseStringUTFChars(s, mCStrings[ct]);
+        }
+        free(mCStrings);
+        free(mSizeArray);
+    }
+    const char **c_str() const { return mCStrings; }
+    size_t *c_str_len() const { return mSizeArray; }
+    jsize length() const { return mStringsLength; }
+
+private:
+    JNIEnv      *mEnv;
+    jobjectArray mStrings;
+    const char **mCStrings;
+    size_t      *mSizeArray;
+    jsize        mStringsLength;
+};
+
 // ---------------------------------------------------------------------------
 
 static jfieldID gContextId = 0;
@@ -322,33 +356,27 @@
 }
 
 static jint
-nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names, jintArray _arraySizes)
+nElementCreate2(JNIEnv *_env, jobject _this, RsContext con,
+                jintArray _ids, jobjectArray _names, jintArray _arraySizes)
 {
     int fieldCount = _env->GetArrayLength(_ids);
     LOG_API("nElementCreate2, con(%p)", con);
 
     jint *ids = _env->GetIntArrayElements(_ids, NULL);
     jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
-    const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *));
-    size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t));
 
-    for (int ct=0; ct < fieldCount; ct++) {
-        jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
-        nameArray[ct] = _env->GetStringUTFChars(s, NULL);
-        sizeArray[ct] = _env->GetStringUTFLength(s);
-    }
+    AutoJavaStringArrayToUTF8 names(_env, _names, fieldCount);
+
+    const char **nameArray = names.c_str();
+    size_t *sizeArray = names.c_str_len();
+
     jint id = (jint)rsElementCreate2(con,
                                      (RsElement *)ids, fieldCount,
                                      nameArray, fieldCount * sizeof(size_t),  sizeArray,
                                      (const uint32_t *)arraySizes, fieldCount);
-    for (int ct=0; ct < fieldCount; ct++) {
-        jstring s = (jstring)_env->GetObjectArrayElement(_names, ct);
-        _env->ReleaseStringUTFChars(s, nameArray[ct]);
-    }
+
     _env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT);
     _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT);
-    free(nameArray);
-    free(sizeArray);
     return (jint)id;
 }
 
@@ -1064,15 +1092,24 @@
 // ---------------------------------------------------------------------------
 
 static jint
-nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params)
+nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader,
+                       jobjectArray texNames, jintArray params)
 {
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
     jint paramLen = _env->GetArrayLength(params);
 
+    int texCount = _env->GetArrayLength(texNames);
+    AutoJavaStringArrayToUTF8 names(_env, texNames, texCount);
+    const char ** nameArray = names.c_str();
+    size_t* sizeArray = names.c_str_len();
+
     LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen);
 
-    jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
+    jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(),
+                                             nameArray, texCount, sizeArray,
+                                             (uint32_t *)paramPtr, paramLen);
+
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
     return ret;
 }
@@ -1081,7 +1118,8 @@
 // ---------------------------------------------------------------------------
 
 static jint
-nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params)
+nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader,
+                     jobjectArray texNames, jintArray params)
 {
     AutoJavaStringToUTF8 shaderUTF(_env, shader);
     jint *paramPtr = _env->GetIntArrayElements(params, NULL);
@@ -1089,7 +1127,15 @@
 
     LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", con, paramLen);
 
-    jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen);
+    int texCount = _env->GetArrayLength(texNames);
+    AutoJavaStringArrayToUTF8 names(_env, texNames, texCount);
+    const char ** nameArray = names.c_str();
+    size_t* sizeArray = names.c_str_len();
+
+    jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(),
+                                           nameArray, texCount, sizeArray,
+                                           (uint32_t *)paramPtr, paramLen);
+
     _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT);
     return ret;
 }
@@ -1351,9 +1397,9 @@
 {"rsnProgramBindTexture",            "(IIII)V",                               (void*)nProgramBindTexture },
 {"rsnProgramBindSampler",            "(IIII)V",                               (void*)nProgramBindSampler },
 
-{"rsnProgramFragmentCreate",         "(ILjava/lang/String;[I)I",              (void*)nProgramFragmentCreate },
+{"rsnProgramFragmentCreate",         "(ILjava/lang/String;[Ljava/lang/String;[I)I",              (void*)nProgramFragmentCreate },
 {"rsnProgramRasterCreate",           "(IZI)I",                                (void*)nProgramRasterCreate },
-{"rsnProgramVertexCreate",           "(ILjava/lang/String;[I)I",              (void*)nProgramVertexCreate },
+{"rsnProgramVertexCreate",           "(ILjava/lang/String;[Ljava/lang/String;[I)I",              (void*)nProgramVertexCreate },
 
 {"rsnContextBindRootScript",         "(II)V",                                 (void*)nContextBindRootScript },
 {"rsnContextBindProgramStore",       "(II)V",                                 (void*)nContextBindProgramStore },
diff --git a/include/android_runtime/android_app_NativeActivity.h b/include/android_runtime/android_app_NativeActivity.h
index 93fcf69..a59677a 100644
--- a/include/android_runtime/android_app_NativeActivity.h
+++ b/include/android_runtime/android_app_NativeActivity.h
@@ -17,7 +17,7 @@
 #ifndef _ANDROID_APP_NATIVEACTIVITY_H
 #define _ANDROID_APP_NATIVEACTIVITY_H
 
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 #include <utils/Looper.h>
 
 #include <android/native_activity.h>
diff --git a/include/android_runtime/android_content_res_Configuration.h b/include/android_runtime/android_content_res_Configuration.h
index 2f5a982..34c4439 100644
--- a/include/android_runtime/android_content_res_Configuration.h
+++ b/include/android_runtime/android_content_res_Configuration.h
@@ -17,7 +17,7 @@
 #ifndef _ANDROID_CONTENT_RES_CONFIGURATION_H
 #define _ANDROID_CONTENT_RES_CONFIGURATION_H
 
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 #include <android/configuration.h>
 
 #include "jni.h"
diff --git a/include/android_runtime/android_util_AssetManager.h b/include/android_runtime/android_util_AssetManager.h
index b6dd9c9..8dd9337 100644
--- a/include/android_runtime/android_util_AssetManager.h
+++ b/include/android_runtime/android_util_AssetManager.h
@@ -17,7 +17,7 @@
 #ifndef android_util_AssetManager_H
 #define android_util_AssetManager_H
 
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
 
 #include "jni.h"
 
diff --git a/include/utils/Asset.h b/include/androidfw/Asset.h
similarity index 100%
rename from include/utils/Asset.h
rename to include/androidfw/Asset.h
diff --git a/include/utils/AssetDir.h b/include/androidfw/AssetDir.h
similarity index 100%
rename from include/utils/AssetDir.h
rename to include/androidfw/AssetDir.h
diff --git a/include/utils/AssetManager.h b/include/androidfw/AssetManager.h
similarity index 98%
rename from include/utils/AssetManager.h
rename to include/androidfw/AssetManager.h
index a8c7ddb..d95b45e 100644
--- a/include/utils/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -20,14 +20,15 @@
 #ifndef __LIBS_ASSETMANAGER_H
 #define __LIBS_ASSETMANAGER_H
 
-#include <utils/Asset.h>
-#include <utils/AssetDir.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetDir.h>
+#include <androidfw/ZipFileRO.h>
 #include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/Vector.h>
+#include <utils/SortedVector.h>
 #include <utils/String16.h>
-#include <utils/ZipFileRO.h>
+#include <utils/String8.h>
 #include <utils/threads.h>
+#include <utils/Vector.h>
 
 /*
  * Native-app access is via the opaque typedef struct AAssetManager in the C namespace.
diff --git a/include/utils/BackupHelpers.h b/include/androidfw/BackupHelpers.h
similarity index 100%
rename from include/utils/BackupHelpers.h
rename to include/androidfw/BackupHelpers.h
diff --git a/include/ui/Input.h b/include/androidfw/Input.h
similarity index 99%
rename from include/ui/Input.h
rename to include/androidfw/Input.h
index c2cbe1d..f5db6e24 100644
--- a/include/ui/Input.h
+++ b/include/androidfw/Input.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _UI_INPUT_H
-#define _UI_INPUT_H
+#ifndef _ANDROIDFW_INPUT_H
+#define _ANDROIDFW_INPUT_H
 
 /**
  * Native input event structures.
@@ -894,4 +894,4 @@
 
 } // namespace android
 
-#endif // _UI_INPUT_H
+#endif // _ANDROIDFW_INPUT_H
diff --git a/include/ui/InputTransport.h b/include/androidfw/InputTransport.h
similarity index 98%
rename from include/ui/InputTransport.h
rename to include/androidfw/InputTransport.h
index 0facce3..a846e65 100644
--- a/include/ui/InputTransport.h
+++ b/include/androidfw/InputTransport.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _UI_INPUT_TRANSPORT_H
-#define _UI_INPUT_TRANSPORT_H
+#ifndef _ANDROIDFW_INPUT_TRANSPORT_H
+#define _ANDROIDFW_INPUT_TRANSPORT_H
 
 /**
  * Native input transport.
@@ -27,11 +27,12 @@
  * The InputConsumer is used by the application to receive events from the input dispatcher.
  */
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
+#include <utils/Vector.h>
 
 namespace android {
 
@@ -332,4 +333,4 @@
 
 } // namespace android
 
-#endif // _UI_INPUT_TRANSPORT_H
+#endif // _ANDROIDFW_INPUT_TRANSPORT_H
diff --git a/include/ui/KeyCharacterMap.h b/include/androidfw/KeyCharacterMap.h
similarity index 97%
rename from include/ui/KeyCharacterMap.h
rename to include/androidfw/KeyCharacterMap.h
index be14432..679dd2c 100644
--- a/include/ui/KeyCharacterMap.h
+++ b/include/androidfw/KeyCharacterMap.h
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef _UI_KEY_CHARACTER_MAP_H
-#define _UI_KEY_CHARACTER_MAP_H
+#ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H
+#define _ANDROIDFW_KEY_CHARACTER_MAP_H
 
 #include <stdint.h>
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Tokenizer.h>
@@ -196,4 +196,4 @@
 
 } // namespace android
 
-#endif // _UI_KEY_CHARACTER_MAP_H
+#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/include/ui/KeyLayoutMap.h b/include/androidfw/KeyLayoutMap.h
similarity index 95%
rename from include/ui/KeyLayoutMap.h
rename to include/androidfw/KeyLayoutMap.h
index d82d0c8..5a6f550 100644
--- a/include/ui/KeyLayoutMap.h
+++ b/include/androidfw/KeyLayoutMap.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _UI_KEY_LAYOUT_MAP_H
-#define _UI_KEY_LAYOUT_MAP_H
+#ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H
+#define _ANDROIDFW_KEY_LAYOUT_MAP_H
 
 #include <stdint.h>
 #include <utils/Errors.h>
@@ -96,4 +96,4 @@
 
 } // namespace android
 
-#endif // _UI_KEY_LAYOUT_MAP_H
+#endif // _ANDROIDFW_KEY_LAYOUT_MAP_H
diff --git a/include/ui/Keyboard.h b/include/androidfw/Keyboard.h
similarity index 96%
rename from include/ui/Keyboard.h
rename to include/androidfw/Keyboard.h
index 274f526..ae65198 100644
--- a/include/ui/Keyboard.h
+++ b/include/androidfw/Keyboard.h
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#ifndef _UI_KEYBOARD_H
-#define _UI_KEYBOARD_H
+#ifndef _ANDROIDFW_KEYBOARD_H
+#define _ANDROIDFW_KEYBOARD_H
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <utils/Errors.h>
 #include <utils/String8.h>
 #include <utils/PropertyMap.h>
@@ -116,4 +116,4 @@
 
 } // namespace android
 
-#endif // _UI_KEYBOARD_H
+#endif // _ANDROIDFW_KEYBOARD_H
diff --git a/include/ui/KeycodeLabels.h b/include/androidfw/KeycodeLabels.h
similarity index 98%
rename from include/ui/KeycodeLabels.h
rename to include/androidfw/KeycodeLabels.h
index c5bd0c5..9e4dfcb 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/androidfw/KeycodeLabels.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _UI_KEYCODE_LABELS_H
-#define _UI_KEYCODE_LABELS_H
+#ifndef _ANDROIDFW_KEYCODE_LABELS_H
+#define _ANDROIDFW_KEYCODE_LABELS_H
 
 #include <android/keycodes.h>
 
@@ -307,4 +307,4 @@
     { NULL, -1 }
 };
 
-#endif // _UI_KEYCODE_LABELS_H
+#endif // _ANDROIDFW_KEYCODE_LABELS_H
diff --git a/include/utils/ObbFile.h b/include/androidfw/ObbFile.h
similarity index 100%
rename from include/utils/ObbFile.h
rename to include/androidfw/ObbFile.h
diff --git a/include/ui/PowerManager.h b/include/androidfw/PowerManager.h
similarity index 88%
rename from include/ui/PowerManager.h
rename to include/androidfw/PowerManager.h
index dd80318..59e993a 100644
--- a/include/ui/PowerManager.h
+++ b/include/androidfw/PowerManager.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef _UI_POWER_MANAGER_H
-#define _UI_POWER_MANAGER_H
+#ifndef _ANDROIDFW_POWER_MANAGER_H
+#define _ANDROIDFW_POWER_MANAGER_H
 
 
 namespace android {
@@ -30,4 +30,4 @@
 
 } // namespace android
 
-#endif // _UI_POWER_MANAGER_H
+#endif // _ANDROIDFW_POWER_MANAGER_H
diff --git a/include/utils/ResourceTypes.h b/include/androidfw/ResourceTypes.h
similarity index 99%
rename from include/utils/ResourceTypes.h
rename to include/androidfw/ResourceTypes.h
index c496da6..23bca3e 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -20,7 +20,7 @@
 #ifndef _LIBS_UTILS_RESOURCE_TYPES_H
 #define _LIBS_UTILS_RESOURCE_TYPES_H
 
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
 #include <utils/ByteOrder.h>
 #include <utils/Errors.h>
 #include <utils/String16.h>
diff --git a/include/utils/StreamingZipInflater.h b/include/androidfw/StreamingZipInflater.h
similarity index 100%
rename from include/utils/StreamingZipInflater.h
rename to include/androidfw/StreamingZipInflater.h
diff --git a/include/ui/VirtualKeyMap.h b/include/androidfw/VirtualKeyMap.h
similarity index 92%
rename from include/ui/VirtualKeyMap.h
rename to include/androidfw/VirtualKeyMap.h
index 7813d9d..66340e3 100644
--- a/include/ui/VirtualKeyMap.h
+++ b/include/androidfw/VirtualKeyMap.h
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef _UI_VIRTUAL_KEY_MAP_H
-#define _UI_VIRTUAL_KEY_MAP_H
+#ifndef _ANDROIDFW_VIRTUAL_KEY_MAP_H
+#define _ANDROIDFW_VIRTUAL_KEY_MAP_H
 
 #include <stdint.h>
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/Tokenizer.h>
@@ -76,4 +76,4 @@
 
 } // namespace android
 
-#endif // _UI_KEY_CHARACTER_MAP_H
+#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H
diff --git a/include/utils/ZipFileCRO.h b/include/androidfw/ZipFileCRO.h
similarity index 100%
rename from include/utils/ZipFileCRO.h
rename to include/androidfw/ZipFileCRO.h
diff --git a/include/utils/ZipFileRO.h b/include/androidfw/ZipFileRO.h
similarity index 100%
rename from include/utils/ZipFileRO.h
rename to include/androidfw/ZipFileRO.h
diff --git a/include/utils/ZipUtils.h b/include/androidfw/ZipUtils.h
similarity index 100%
rename from include/utils/ZipUtils.h
rename to include/androidfw/ZipUtils.h
diff --git a/include/common_time/ICommonClock.h b/include/common_time/ICommonClock.h
new file mode 100644
index 0000000..d7073f1
--- /dev/null
+++ b/include/common_time/ICommonClock.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ICOMMONCLOCK_H
+#define ANDROID_ICOMMONCLOCK_H
+
+#include <stdint.h>
+#include <linux/socket.h>
+
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class ICommonClockListener : public IInterface {
+  public:
+    DECLARE_META_INTERFACE(CommonClockListener);
+
+    virtual void onTimelineChanged(uint64_t timelineID) = 0;
+};
+
+class BnCommonClockListener : public BnInterface<ICommonClockListener> {
+  public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+class ICommonClock : public IInterface {
+  public:
+    DECLARE_META_INTERFACE(CommonClock);
+
+    // Name of the ICommonClock service registered with the service manager.
+    static const String16 kServiceName;
+
+    // a reserved invalid timeline ID
+    static const uint64_t kInvalidTimelineID;
+
+    // a reserved invalid error estimate
+    static const int32_t kErrorEstimateUnknown;
+
+    enum State {
+        // the device just came up and is trying to discover the master
+        STATE_INITIAL,
+
+        // the device is a client of a master
+        STATE_CLIENT,
+
+        // the device is acting as master
+        STATE_MASTER,
+
+        // the device has lost contact with its master and needs to participate
+        // in the election of a new master
+        STATE_RONIN,
+
+        // the device is waiting for announcement of the newly elected master
+        STATE_WAIT_FOR_ELECTION,
+    };
+
+    virtual status_t isCommonTimeValid(bool* valid, uint32_t* timelineID) = 0;
+    virtual status_t commonTimeToLocalTime(int64_t commonTime,
+                                           int64_t* localTime) = 0;
+    virtual status_t localTimeToCommonTime(int64_t localTime,
+                                           int64_t* commonTime) = 0;
+    virtual status_t getCommonTime(int64_t* commonTime) = 0;
+    virtual status_t getCommonFreq(uint64_t* freq) = 0;
+    virtual status_t getLocalTime(int64_t* localTime) = 0;
+    virtual status_t getLocalFreq(uint64_t* freq) = 0;
+    virtual status_t getEstimatedError(int32_t* estimate) = 0;
+    virtual status_t getTimelineID(uint64_t* id) = 0;
+    virtual status_t getState(State* state) = 0;
+    virtual status_t getMasterAddr(struct sockaddr_storage* addr) = 0;
+
+    virtual status_t registerListener(
+            const sp<ICommonClockListener>& listener) = 0;
+    virtual status_t unregisterListener(
+            const sp<ICommonClockListener>& listener) = 0;
+
+    // Simple helper to make it easier to connect to the CommonClock service.
+    static inline sp<ICommonClock> getInstance() {
+        sp<IBinder> binder = defaultServiceManager()->checkService(
+                ICommonClock::kServiceName);
+        sp<ICommonClock> clk = interface_cast<ICommonClock>(binder);
+        return clk;
+    }
+};
+
+class BnCommonClock : public BnInterface<ICommonClock> {
+  public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+};  // namespace android
+
+#endif  // ANDROID_ICOMMONCLOCK_H
diff --git a/include/common_time/ICommonTimeConfig.h b/include/common_time/ICommonTimeConfig.h
new file mode 100644
index 0000000..497b666
--- /dev/null
+++ b/include/common_time/ICommonTimeConfig.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_ICOMMONTIMECONFIG_H
+#define ANDROID_ICOMMONTIMECONFIG_H
+
+#include <stdint.h>
+#include <linux/socket.h>
+
+#include <binder/IInterface.h>
+#include <binder/IServiceManager.h>
+
+namespace android {
+
+class String16;
+
+class ICommonTimeConfig : public IInterface {
+  public:
+    DECLARE_META_INTERFACE(CommonTimeConfig);
+
+    // Name of the ICommonTimeConfig service registered with the service
+    // manager.
+    static const String16 kServiceName;
+
+    virtual status_t getMasterElectionPriority(uint8_t *priority) = 0;
+    virtual status_t setMasterElectionPriority(uint8_t priority) = 0;
+    virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr) = 0;
+    virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr) = 0;
+    virtual status_t getMasterElectionGroupId(uint64_t *id) = 0;
+    virtual status_t setMasterElectionGroupId(uint64_t id) = 0;
+    virtual status_t getInterfaceBinding(String16& ifaceName) = 0;
+    virtual status_t setInterfaceBinding(const String16& ifaceName) = 0;
+    virtual status_t getMasterAnnounceInterval(int *interval) = 0;
+    virtual status_t setMasterAnnounceInterval(int interval) = 0;
+    virtual status_t getClientSyncInterval(int *interval) = 0;
+    virtual status_t setClientSyncInterval(int interval) = 0;
+    virtual status_t getPanicThreshold(int *threshold) = 0;
+    virtual status_t setPanicThreshold(int threshold) = 0;
+    virtual status_t getAutoDisable(bool *autoDisable) = 0;
+    virtual status_t setAutoDisable(bool autoDisable) = 0;
+    virtual status_t forceNetworklessMasterMode() = 0;
+
+    // Simple helper to make it easier to connect to the CommonTimeConfig service.
+    static inline sp<ICommonTimeConfig> getInstance() {
+        sp<IBinder> binder = defaultServiceManager()->checkService(
+                ICommonTimeConfig::kServiceName);
+        sp<ICommonTimeConfig> clk = interface_cast<ICommonTimeConfig>(binder);
+        return clk;
+    }
+};
+
+class BnCommonTimeConfig : public BnInterface<ICommonTimeConfig> {
+  public:
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+                                Parcel* reply, uint32_t flags = 0);
+};
+
+};  // namespace android
+
+#endif  // ANDROID_ICOMMONTIMECONFIG_H
diff --git a/include/common_time/cc_helper.h b/include/common_time/cc_helper.h
new file mode 100644
index 0000000..8c4d5c0
--- /dev/null
+++ b/include/common_time/cc_helper.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CC_HELPER_H__
+#define __CC_HELPER_H__
+
+#include <stdint.h>
+#include <common_time/ICommonClock.h>
+#include <utils/threads.h>
+
+namespace android {
+
+// CCHelper is a simple wrapper class to help with centralizing access to the
+// Common Clock service and implementing lifetime managment, as well as to
+// implement a simple policy of making a basic attempt to reconnect to the
+// common clock service when things go wrong.
+//
+// On platforms which run the native common_time service in auto-disable mode,
+// the service will go into networkless mode whenever it has no active clients.
+// It tracks active clients using registered CommonClockListeners (the callback
+// interface for onTimelineChanged) since this provides a convienent death
+// handler notification for when the service's clients die unexpectedly.  This
+// means that users of the common time service should really always have a
+// CommonClockListener, unless they know that the time service is not running in
+// auto disabled mode, or that there is at least one other registered listener
+// active in the system.  The CCHelper makes this a little easier by sharing a
+// ref counted ICommonClock interface across all clients and automatically
+// registering and unregistering a listener whenever there are CCHelper
+// instances active in the process.
+class CCHelper {
+  public:
+    CCHelper();
+    ~CCHelper();
+
+    status_t isCommonTimeValid(bool* valid, uint32_t* timelineID);
+    status_t commonTimeToLocalTime(int64_t commonTime, int64_t* localTime);
+    status_t localTimeToCommonTime(int64_t localTime, int64_t* commonTime);
+    status_t getCommonTime(int64_t* commonTime);
+    status_t getCommonFreq(uint64_t* freq);
+    status_t getLocalTime(int64_t* localTime);
+    status_t getLocalFreq(uint64_t* freq);
+
+  private:
+    class CommonClockListener : public BnCommonClockListener {
+      public:
+        void onTimelineChanged(uint64_t timelineID);
+    };
+
+    static bool verifyClock_l();
+
+    static Mutex lock_;
+    static sp<ICommonClock> common_clock_;
+    static sp<ICommonClockListener> common_clock_listener_;
+    static uint32_t ref_count_;
+};
+
+
+}  // namespace android
+#endif  // __CC_HELPER_H__
diff --git a/include/common_time/local_clock.h b/include/common_time/local_clock.h
new file mode 100644
index 0000000..845d1c21
--- /dev/null
+++ b/include/common_time/local_clock.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef __LOCAL_CLOCK_H__
+#define __LOCAL_CLOCK_H__
+
+#include <stdint.h>
+
+#include <hardware/local_time_hal.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class LocalClock {
+  public:
+     LocalClock();
+
+    bool initCheck();
+
+    int64_t  getLocalTime();
+    uint64_t getLocalFreq();
+    status_t setLocalSlew(int16_t rate);
+    int32_t  getDebugLog(struct local_time_debug_event* records,
+                         int max_records);
+
+  private:
+    static Mutex dev_lock_;
+    static local_time_hw_device_t* dev_;
+};
+
+}  // namespace android
+#endif  // __LOCAL_CLOCK_H__
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index ac7f6cf..9f2bd3a 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -446,7 +446,7 @@
      */
             status_t dump(int fd, const Vector<String16>& args) const;
 
-private:
+protected:
     /* copying audio tracks is not allowed */
                         AudioTrack(const AudioTrack& other);
             AudioTrack& operator = (const AudioTrack& other);
@@ -518,10 +518,33 @@
     int                     mAuxEffectId;
     mutable Mutex           mLock;
     status_t                mRestoreStatus;
+    bool                    mIsTimed;
     int                     mPreviousPriority;          // before start()
     int                     mPreviousSchedulingGroup;
 };
 
+class TimedAudioTrack : public AudioTrack
+{
+public:
+    TimedAudioTrack();
+
+    /* allocate a shared memory buffer that can be passed to queueTimedBuffer */
+    status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer);
+
+    /* queue a buffer obtained via allocateTimedBuffer for playback at the
+       given timestamp.  PTS units a microseconds on the media time timeline.
+       The media time transform (set with setMediaTimeTransform) set by the
+       audio producer will handle converting from media time to local time
+       (perhaps going through the common time timeline in the case of
+       synchronized multiroom audio case) */
+    status_t queueTimedBuffer(const sp<IMemory>& buffer, int64_t pts);
+
+    /* define a transform between media time and either common time or
+       local time */
+    enum TargetTimeline {LOCAL_TIME, COMMON_TIME};
+    status_t setMediaTimeTransform(const LinearTransform& xform,
+                                   TargetTimeline target);
+};
 
 }; // namespace android
 
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 433ce7c..7a2ada0 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -55,6 +55,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
+                                bool isTimed,
                                 int *sessionId,
                                 status_t *status) = 0;
 
diff --git a/include/media/IAudioTrack.h b/include/media/IAudioTrack.h
index e4772a1..77f3e21 100644
--- a/include/media/IAudioTrack.h
+++ b/include/media/IAudioTrack.h
@@ -24,7 +24,7 @@
 #include <utils/Errors.h>
 #include <binder/IInterface.h>
 #include <binder/IMemory.h>
-
+#include <utils/LinearTransform.h>
 
 namespace android {
 
@@ -71,6 +71,23 @@
      */
     virtual status_t    attachAuxEffect(int effectId) = 0;
 
+
+    /* Allocate a shared memory buffer suitable for holding timed audio
+       samples */
+    virtual status_t    allocateTimedBuffer(size_t size,
+                                            sp<IMemory>* buffer) = 0;
+
+    /* Queue a buffer obtained via allocateTimedBuffer for playback at the given
+       timestamp */
+    virtual status_t    queueTimedBuffer(const sp<IMemory>& buffer,
+                                         int64_t pts) = 0;
+
+    /* Define the linear transform that will be applied to the timestamps
+       given to queueTimedBuffer (which are expressed in media time).
+       Target specifies whether this transform converts media time to local time
+       or Tungsten time. The values for target are defined in AudioTrack.h */
+    virtual status_t    setMediaTimeTransform(const LinearTransform& xform,
+                                              int target) = 0;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 77c82b2..23a3e49 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -46,6 +46,9 @@
     // The shared library with the test player is passed passed as an
     // argument to the 'test:' url in the setDataSource call.
     TEST_PLAYER = 5,
+
+    AAH_RX_PLAYER = 100,
+    AAH_TX_PLAYER = 101,
 };
 
 
diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h
index 79437bf..f5466e8 100644
--- a/include/media/stagefright/AudioSource.h
+++ b/include/media/stagefright/AudioSource.h
@@ -95,6 +95,7 @@
         int32_t startFrame, int32_t rampDurationFrames,
         uint8_t *data,   size_t bytes);
 
+    void queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs);
     void releaseQueuedFrames_l();
     void waitOutstandingEncodingFrames_l();
     status_t reset();
diff --git a/include/ui/PixelFormat.h b/include/ui/PixelFormat.h
index 848c5a1..fc260c4 100644
--- a/include/ui/PixelFormat.h
+++ b/include/ui/PixelFormat.h
@@ -21,7 +21,6 @@
 // skia or SurfaceFlinger are not required to support all of these formats
 // (either as source or destination)
 
-// XXX: we should consolidate these formats and skia's
 
 #ifndef UI_PIXELFORMAT_H
 #define UI_PIXELFORMAT_H
@@ -29,7 +28,6 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <utils/Errors.h>
-#include <pixelflinger/format.h>
 #include <hardware/hardware.h>
 
 namespace android {
@@ -65,10 +63,7 @@
     PIXEL_FORMAT_BGRA_8888   = HAL_PIXEL_FORMAT_BGRA_8888,  // 4x8-bit BGRA
     PIXEL_FORMAT_RGBA_5551   = HAL_PIXEL_FORMAT_RGBA_5551,  // 16-bit ARGB
     PIXEL_FORMAT_RGBA_4444   = HAL_PIXEL_FORMAT_RGBA_4444,  // 16-bit ARGB
-    PIXEL_FORMAT_A_8         = GGL_PIXEL_FORMAT_A_8,        // 8-bit A
-    PIXEL_FORMAT_L_8         = GGL_PIXEL_FORMAT_L_8,        // 8-bit L (R=G=B=L)
-    PIXEL_FORMAT_LA_88       = GGL_PIXEL_FORMAT_LA_88,      // 16-bit LA
-    PIXEL_FORMAT_RGB_332     = GGL_PIXEL_FORMAT_RGB_332,    // 8-bit RGB
+    PIXEL_FORMAT_A_8         = 8,                           // 8-bit A
 
     // New formats can be added if they're also defined in
     // pixelflinger/format.h
@@ -76,8 +71,7 @@
 
 typedef int32_t PixelFormat;
 
-struct PixelFormatInfo
-{
+struct PixelFormatInfo {
     enum {
         INDEX_ALPHA   = 0,
         INDEX_RED     = 1,
@@ -89,8 +83,6 @@
         ALPHA               = 1,
         RGB                 = 2,
         RGBA                = 3,
-        LUMINANCE           = 4,
-        LUMINANCE_ALPHA     = 5,
         OTHER               = 0xFF
     };
 
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index db6388a..0fe7bd8 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -124,7 +124,7 @@
     public static final String EXTRA_SENDER = "sender";
 
     /**
-     * Action to bring up the CertInstaller
+     * Action to bring up the CertInstaller.
      */
     private static final String ACTION_INSTALL = "android.credentials.INSTALL";
 
@@ -167,6 +167,22 @@
     // Compatible with old android.security.Credentials.PKCS12
     public static final String EXTRA_PKCS12 = "PKCS12";
 
+
+    /**
+     * @hide TODO This is temporary and will be removed
+     * Broadcast Action: Indicates the trusted storage has changed. Sent when
+     * one of this happens:
+     *
+     * <ul>
+     * <li>a new CA is added,
+     * <li>an existing CA is removed or disabled,
+     * <li>a disabled CA is enabled,
+     * <li>trusted storage is reset (all user certs are cleared),
+     * <li>when permission to access a private key is changed.
+     * </ul>
+     */
+    public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
+
     /**
      * Returns an {@code Intent} that can be used for credential
      * installation. The intent may be used without any extras, in
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
new file mode 100644
index 0000000..c5f8a87
--- /dev/null
+++ b/libs/androidfw/Android.mk
@@ -0,0 +1,113 @@
+# Copyright (C) 2010 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.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# libandroidfw is partially built for the host (used by build time keymap validation tool)
+# These files are common to host and target builds.
+
+# formerly in libutils
+commonUtilsSources:= \
+    Asset.cpp \
+    AssetDir.cpp \
+    AssetManager.cpp \
+    ObbFile.cpp \
+    ResourceTypes.cpp \
+    StreamingZipInflater.cpp \
+    ZipFileCRO.cpp \
+    ZipFileRO.cpp \
+    ZipUtils.cpp
+
+# formerly in libui
+commonUiSources:= \
+    Input.cpp \
+    Keyboard.cpp \
+    KeyCharacterMap.cpp \
+    KeyLayoutMap.cpp \
+    VirtualKeyMap.cpp
+
+commonSources:= \
+	$(commonUtilsSources) \
+	$(commonUiSources)
+
+# For the host
+# =====================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= $(commonSources)
+
+LOCAL_MODULE:= libandroidfw
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_C_INCLUDES := \
+	external/zlib
+
+include $(BUILD_HOST_STATIC_LIBRARY)
+
+
+# For the device
+# =====================================================
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	$(commonSources) \
+	BackupData.cpp \
+	BackupHelpers.cpp \
+	InputTransport.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	liblog \
+	libcutils \
+	libutils \
+	libbinder \
+	libskia \
+	libz
+
+LOCAL_C_INCLUDES := \
+    external/skia/include/core \
+    external/icu4c/common \
+	external/zlib
+
+LOCAL_MODULE:= libandroidfw
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
+
+ifeq ($(TARGET_OS),linux)
+include $(CLEAR_VARS)
+LOCAL_C_INCLUDES += \
+	external/skia/include/core \
+	external/zlib \
+	external/icu4c/common \
+	bionic/libc/private
+LOCAL_LDLIBS := -lrt -ldl -lpthread
+LOCAL_MODULE := libandroidfw
+LOCAL_SRC_FILES := $(commonUtilsSources) BackupData.cpp BackupHelpers.cpp
+include $(BUILD_STATIC_LIBRARY)
+endif
+
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/libs/utils/Asset.cpp b/libs/androidfw/Asset.cpp
similarity index 98%
rename from libs/utils/Asset.cpp
rename to libs/androidfw/Asset.cpp
index 50e701a..cb7628d 100644
--- a/libs/utils/Asset.cpp
+++ b/libs/androidfw/Asset.cpp
@@ -21,23 +21,23 @@
 #define LOG_TAG "asset"
 //#define NDEBUG 0
 
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
+#include <androidfw/StreamingZipInflater.h>
+#include <androidfw/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
 #include <utils/Atomic.h>
 #include <utils/FileMap.h>
-#include <utils/StreamingZipInflater.h>
-#include <utils/ZipUtils.h>
-#include <utils/ZipFileRO.h>
 #include <utils/Log.h>
 #include <utils/threads.h>
 
-#include <string.h>
-#include <memory.h>
-#include <fcntl.h>
-#include <errno.h>
 #include <assert.h>
-#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <string.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <unistd.h>
 
 using namespace android;
 
diff --git a/libs/utils/AssetDir.cpp b/libs/androidfw/AssetDir.cpp
similarity index 97%
rename from libs/utils/AssetDir.cpp
rename to libs/androidfw/AssetDir.cpp
index c5f664e..475f521 100644
--- a/libs/utils/AssetDir.cpp
+++ b/libs/androidfw/AssetDir.cpp
@@ -19,7 +19,7 @@
 // implementation is in the header file or in friend functions in
 // AssetManager.
 //
-#include <utils/AssetDir.h>
+#include <androidfw/AssetDir.h>
 
 using namespace android;
 
diff --git a/libs/utils/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
similarity index 99%
rename from libs/utils/AssetManager.cpp
rename to libs/androidfw/AssetManager.cpp
index 47a2b99..4829add 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -21,23 +21,23 @@
 #define LOG_TAG "asset"
 //#define LOG_NDEBUG 0
 
-#include <utils/AssetManager.h>
-#include <utils/AssetDir.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetDir.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
+#include <androidfw/ZipFileRO.h>
 #include <utils/Atomic.h>
-#include <utils/String8.h>
-#include <utils/ResourceTypes.h>
-#include <utils/String8.h>
-#include <utils/ZipFileRO.h>
 #include <utils/Log.h>
-#include <utils/Timers.h>
+#include <utils/String8.h>
+#include <utils/String8.h>
 #include <utils/threads.h>
+#include <utils/Timers.h>
 
+#include <assert.h>
 #include <dirent.h>
 #include <errno.h>
-#include <assert.h>
-#include <strings.h>
 #include <fcntl.h>
+#include <strings.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
diff --git a/libs/utils/BackupData.cpp b/libs/androidfw/BackupData.cpp
similarity index 99%
rename from libs/utils/BackupData.cpp
rename to libs/androidfw/BackupData.cpp
index f956306..7b1bcba 100644
--- a/libs/utils/BackupData.cpp
+++ b/libs/androidfw/BackupData.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "backup_data"
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 #include <utils/ByteOrder.h>
 
 #include <stdio.h>
diff --git a/libs/utils/BackupHelpers.cpp b/libs/androidfw/BackupHelpers.cpp
similarity index 99%
rename from libs/utils/BackupHelpers.cpp
rename to libs/androidfw/BackupHelpers.cpp
index f77a891..7a817a7 100644
--- a/libs/utils/BackupHelpers.cpp
+++ b/libs/androidfw/BackupHelpers.cpp
@@ -16,7 +16,7 @@
 
 #define LOG_TAG "file_backup_helper"
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 
 #include <utils/KeyedVector.h>
 #include <utils/ByteOrder.h>
@@ -546,7 +546,7 @@
 
     // read/write up to this much at a time.
     const size_t BUFSIZE = 32 * 1024;
-    char* buf = new char[BUFSIZE];
+    char* buf = (char *)calloc(1,BUFSIZE);
     char* paxHeader = buf + 512;    // use a different chunk of it as separate scratch
     char* paxData = buf + 1024;
 
@@ -556,9 +556,6 @@
         goto cleanup;
     }
 
-    // Good to go -- first construct the standard tar header at the start of the buffer
-    memset(buf, 0, BUFSIZE);
-
     // Magic fields for the ustar file format
     strcat(buf + 257, "ustar");
     strcat(buf + 263, "00");
diff --git a/libs/ui/Input.cpp b/libs/androidfw/Input.cpp
similarity index 99%
rename from libs/ui/Input.cpp
rename to libs/androidfw/Input.cpp
index 263c8d9..ca09caf 100644
--- a/libs/ui/Input.cpp
+++ b/libs/androidfw/Input.cpp
@@ -24,7 +24,7 @@
 #include <unistd.h>
 #include <ctype.h>
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 
 #include <math.h>
 #include <limits.h>
diff --git a/libs/ui/InputTransport.cpp b/libs/androidfw/InputTransport.cpp
similarity index 99%
rename from libs/ui/InputTransport.cpp
rename to libs/androidfw/InputTransport.cpp
index ecb3fb5..1ebd75c 100644
--- a/libs/ui/InputTransport.cpp
+++ b/libs/androidfw/InputTransport.cpp
@@ -20,7 +20,7 @@
 #include <cutils/log.h>
 #include <errno.h>
 #include <fcntl.h>
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/socket.h>
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/androidfw/KeyCharacterMap.cpp
similarity index 99%
rename from libs/ui/KeyCharacterMap.cpp
rename to libs/androidfw/KeyCharacterMap.cpp
index 485234c..6984084 100644
--- a/libs/ui/KeyCharacterMap.cpp
+++ b/libs/androidfw/KeyCharacterMap.cpp
@@ -19,8 +19,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <android/keycodes.h>
-#include <ui/Keyboard.h>
-#include <ui/KeyCharacterMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeyCharacterMap.h>
 #include <utils/Log.h>
 #include <utils/Errors.h>
 #include <utils/Tokenizer.h>
diff --git a/libs/ui/KeyLayoutMap.cpp b/libs/androidfw/KeyLayoutMap.cpp
similarity index 98%
rename from libs/ui/KeyLayoutMap.cpp
rename to libs/androidfw/KeyLayoutMap.cpp
index 44a9420..15d81ee 100644
--- a/libs/ui/KeyLayoutMap.cpp
+++ b/libs/androidfw/KeyLayoutMap.cpp
@@ -18,8 +18,8 @@
 
 #include <stdlib.h>
 #include <android/keycodes.h>
-#include <ui/Keyboard.h>
-#include <ui/KeyLayoutMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeyLayoutMap.h>
 #include <utils/Log.h>
 #include <utils/Errors.h>
 #include <utils/Tokenizer.h>
diff --git a/libs/ui/Keyboard.cpp b/libs/androidfw/Keyboard.cpp
similarity index 98%
rename from libs/ui/Keyboard.cpp
rename to libs/androidfw/Keyboard.cpp
index e4611f7..e97a5eb 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/androidfw/Keyboard.cpp
@@ -20,10 +20,10 @@
 #include <unistd.h>
 #include <limits.h>
 
-#include <ui/Keyboard.h>
-#include <ui/KeycodeLabels.h>
-#include <ui/KeyLayoutMap.h>
-#include <ui/KeyCharacterMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeycodeLabels.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/KeyCharacterMap.h>
 #include <utils/Errors.h>
 #include <utils/Log.h>
 #include <cutils/properties.h>
diff --git a/libs/androidfw/MODULE_LICENSE_APACHE2 b/libs/androidfw/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/libs/androidfw/MODULE_LICENSE_APACHE2
diff --git a/libs/androidfw/NOTICE b/libs/androidfw/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/libs/androidfw/NOTICE
@@ -0,0 +1,190 @@
+
+   Copyright (c) 2005-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.
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
diff --git a/libs/utils/ObbFile.cpp b/libs/androidfw/ObbFile.cpp
similarity index 99%
rename from libs/utils/ObbFile.cpp
rename to libs/androidfw/ObbFile.cpp
index ddf5991..21e06c8 100644
--- a/libs/utils/ObbFile.cpp
+++ b/libs/androidfw/ObbFile.cpp
@@ -23,9 +23,9 @@
 
 #define LOG_TAG "ObbFile"
 
+#include <androidfw/ObbFile.h>
 #include <utils/Compat.h>
 #include <utils/Log.h>
-#include <utils/ObbFile.h>
 
 //#define DEBUG 1
 
diff --git a/libs/utils/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
similarity index 99%
rename from libs/utils/ResourceTypes.cpp
rename to libs/androidfw/ResourceTypes.cpp
index 3fa562e..07f3b16 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -17,14 +17,14 @@
 #define LOG_TAG "ResourceType"
 //#define LOG_NDEBUG 0
 
+#include <androidfw/ResourceTypes.h>
 #include <utils/Atomic.h>
 #include <utils/ByteOrder.h>
 #include <utils/Debug.h>
-#include <utils/ResourceTypes.h>
+#include <utils/Log.h>
 #include <utils/String16.h>
 #include <utils/String8.h>
 #include <utils/TextOutput.h>
-#include <utils/Log.h>
 
 #include <stdlib.h>
 #include <string.h>
@@ -379,8 +379,7 @@
         size_t charSize;
         if (mHeader->flags&ResStringPool_header::UTF8_FLAG) {
             charSize = sizeof(uint8_t);
-            mCache = (char16_t**)malloc(sizeof(char16_t**)*mHeader->stringCount);
-            memset(mCache, 0, sizeof(char16_t**)*mHeader->stringCount);
+            mCache = (char16_t**)calloc(mHeader->stringCount, sizeof(char16_t**));
         } else {
             charSize = sizeof(char16_t);
         }
@@ -3252,16 +3251,14 @@
 
     // Bag not found, we need to compute it!
     if (!grp->bags) {
-        grp->bags = (bag_set***)malloc(sizeof(bag_set*)*grp->typeCount);
+        grp->bags = (bag_set***)calloc(grp->typeCount, sizeof(bag_set*));
         if (!grp->bags) return NO_MEMORY;
-        memset(grp->bags, 0, sizeof(bag_set*)*grp->typeCount);
     }
 
     bag_set** typeSet = grp->bags[t];
     if (!typeSet) {
-        typeSet = (bag_set**)malloc(sizeof(bag_set*)*NENTRY);
+        typeSet = (bag_set**)calloc(NENTRY, sizeof(bag_set*));
         if (!typeSet) return NO_MEMORY;
-        memset(typeSet, 0, sizeof(bag_set*)*NENTRY);
         grp->bags[t] = typeSet;
     }
 
diff --git a/libs/utils/StreamingZipInflater.cpp b/libs/androidfw/StreamingZipInflater.cpp
similarity index 99%
rename from libs/utils/StreamingZipInflater.cpp
rename to libs/androidfw/StreamingZipInflater.cpp
index 8512170a..d3fb98d 100644
--- a/libs/utils/StreamingZipInflater.cpp
+++ b/libs/androidfw/StreamingZipInflater.cpp
@@ -18,8 +18,8 @@
 #define LOG_TAG "szipinf"
 #include <utils/Log.h>
 
+#include <androidfw/StreamingZipInflater.h>
 #include <utils/FileMap.h>
-#include <utils/StreamingZipInflater.h>
 #include <string.h>
 #include <stddef.h>
 #include <assert.h>
diff --git a/libs/ui/VirtualKeyMap.cpp b/libs/androidfw/VirtualKeyMap.cpp
similarity index 98%
rename from libs/ui/VirtualKeyMap.cpp
rename to libs/androidfw/VirtualKeyMap.cpp
index 62d5b59..2ba1673 100644
--- a/libs/ui/VirtualKeyMap.cpp
+++ b/libs/androidfw/VirtualKeyMap.cpp
@@ -18,7 +18,7 @@
 
 #include <stdlib.h>
 #include <string.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/VirtualKeyMap.h>
 #include <utils/Log.h>
 #include <utils/Errors.h>
 #include <utils/Tokenizer.h>
diff --git a/libs/utils/ZipFileCRO.cpp b/libs/androidfw/ZipFileCRO.cpp
similarity index 95%
rename from libs/utils/ZipFileCRO.cpp
rename to libs/androidfw/ZipFileCRO.cpp
index 55dfd9f..c8df845 100644
--- a/libs/utils/ZipFileCRO.cpp
+++ b/libs/androidfw/ZipFileCRO.cpp
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#include <utils/ZipFileCRO.h>
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipFileCRO.h>
+#include <androidfw/ZipFileRO.h>
 
 using namespace android;
 
diff --git a/libs/utils/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
similarity index 99%
rename from libs/utils/ZipFileRO.cpp
rename to libs/androidfw/ZipFileRO.cpp
index 1498aac..4b7f1e7 100644
--- a/libs/utils/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -19,7 +19,7 @@
 //
 #define LOG_TAG "zipro"
 //#define LOG_NDEBUG 0
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipFileRO.h>
 #include <utils/Log.h>
 #include <utils/misc.h>
 #include <utils/threads.h>
diff --git a/libs/utils/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
similarity index 98%
rename from libs/utils/ZipUtils.cpp
rename to libs/androidfw/ZipUtils.cpp
index 2dbdc1d..db3479d 100644
--- a/libs/utils/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -20,8 +20,8 @@
 
 #define LOG_TAG "ziputil"
 
-#include <utils/ZipUtils.h>
-#include <utils/ZipFileRO.h>
+#include <androidfw/ZipUtils.h>
+#include <androidfw/ZipFileRO.h>
 #include <utils/Log.h>
 
 #include <stdlib.h>
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
new file mode 100644
index 0000000..d85009b
--- /dev/null
+++ b/libs/androidfw/tests/Android.mk
@@ -0,0 +1,47 @@
+# Build the unit tests.
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# Build the unit tests.
+test_src_files := \
+    InputChannel_test.cpp \
+    InputEvent_test.cpp \
+    InputPublisherAndConsumer_test.cpp \
+    ObbFile_test.cpp \
+    ZipFileRO_test.cpp 
+
+shared_libraries := \
+	libandroidfw \
+	libcutils \
+	libutils \
+	libbinder \
+	libui \
+	libstlport \
+	libskia
+
+static_libraries := \
+	libgtest \
+	libgtest_main
+
+c_includes := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+    external/skia/include/core
+
+module_tags := eng tests
+
+$(foreach file,$(test_src_files), \
+    $(eval include $(CLEAR_VARS)) \
+    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
+    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
+    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
+    $(eval LOCAL_SRC_FILES := $(file)) \
+    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
+    $(eval include $(BUILD_EXECUTABLE)) \
+)
+
+# Build the manual test programs.
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/ui/tests/InputChannel_test.cpp b/libs/androidfw/tests/InputChannel_test.cpp
similarity index 98%
rename from libs/ui/tests/InputChannel_test.cpp
rename to libs/androidfw/tests/InputChannel_test.cpp
index ee422fe..0e5d19d 100644
--- a/libs/ui/tests/InputChannel_test.cpp
+++ b/libs/androidfw/tests/InputChannel_test.cpp
@@ -14,9 +14,10 @@
  * limitations under the License.
  */
 
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 #include <utils/Timers.h>
 #include <utils/StopWatch.h>
+#include <utils/StrongPointer.h>
 #include <gtest/gtest.h>
 #include <unistd.h>
 #include <time.h>
diff --git a/libs/ui/tests/InputEvent_test.cpp b/libs/androidfw/tests/InputEvent_test.cpp
similarity index 99%
rename from libs/ui/tests/InputEvent_test.cpp
rename to libs/androidfw/tests/InputEvent_test.cpp
index e21c464..ac5549c 100644
--- a/libs/ui/tests/InputEvent_test.cpp
+++ b/libs/androidfw/tests/InputEvent_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <gtest/gtest.h>
 #include <binder/Parcel.h>
 
diff --git a/libs/ui/tests/InputPublisherAndConsumer_test.cpp b/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp
similarity index 99%
rename from libs/ui/tests/InputPublisherAndConsumer_test.cpp
rename to libs/androidfw/tests/InputPublisherAndConsumer_test.cpp
index 3303053..bb45247 100644
--- a/libs/ui/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/androidfw/tests/InputPublisherAndConsumer_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <ui/InputTransport.h>
+#include <androidfw/InputTransport.h>
 #include <utils/Timers.h>
 #include <utils/StopWatch.h>
 #include <gtest/gtest.h>
diff --git a/libs/utils/tests/ObbFile_test.cpp b/libs/androidfw/tests/ObbFile_test.cpp
similarity index 98%
rename from libs/utils/tests/ObbFile_test.cpp
rename to libs/androidfw/tests/ObbFile_test.cpp
index 46b30c2..09d4d7d 100644
--- a/libs/utils/tests/ObbFile_test.cpp
+++ b/libs/androidfw/tests/ObbFile_test.cpp
@@ -15,8 +15,8 @@
  */
 
 #define LOG_TAG "ObbFile_test"
+#include <androidfw/ObbFile.h>
 #include <utils/Log.h>
-#include <utils/ObbFile.h>
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 
diff --git a/libs/utils/tests/ZipFileRO_test.cpp b/libs/androidfw/tests/ZipFileRO_test.cpp
similarity index 97%
rename from libs/utils/tests/ZipFileRO_test.cpp
rename to libs/androidfw/tests/ZipFileRO_test.cpp
index 7a1d0bd..344f974 100644
--- a/libs/utils/tests/ZipFileRO_test.cpp
+++ b/libs/androidfw/tests/ZipFileRO_test.cpp
@@ -15,8 +15,8 @@
  */
 
 #define LOG_TAG "ZipFileRO_test"
+#include <androidfw/ZipFileRO.h>
 #include <utils/Log.h>
-#include <utils/ZipFileRO.h>
 
 #include <gtest/gtest.h>
 
diff --git a/libs/common_time/Android.mk b/libs/common_time/Android.mk
new file mode 100644
index 0000000..526f17b
--- /dev/null
+++ b/libs/common_time/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+#
+# libcommon_time_client
+# (binder marshalers for ICommonClock as well as common clock and local clock
+# helper code)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcommon_time_client
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := cc_helper.cpp \
+                   local_clock.cpp \
+                   ICommonClock.cpp \
+                   ICommonTimeConfig.cpp \
+                   utils.cpp
+LOCAL_SHARED_LIBRARIES := libbinder \
+                          libhardware \
+                          libutils
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/libs/common_time/ICommonClock.cpp b/libs/common_time/ICommonClock.cpp
new file mode 100644
index 0000000..28b43ac
--- /dev/null
+++ b/libs/common_time/ICommonClock.cpp
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <linux/socket.h>
+
+#include <common_time/ICommonClock.h>
+#include <binder/Parcel.h>
+
+#include "utils.h"
+
+namespace android {
+
+/***** ICommonClock *****/
+
+enum {
+    IS_COMMON_TIME_VALID = IBinder::FIRST_CALL_TRANSACTION,
+    COMMON_TIME_TO_LOCAL_TIME,
+    LOCAL_TIME_TO_COMMON_TIME,
+    GET_COMMON_TIME,
+    GET_COMMON_FREQ,
+    GET_LOCAL_TIME,
+    GET_LOCAL_FREQ,
+    GET_ESTIMATED_ERROR,
+    GET_TIMELINE_ID,
+    GET_STATE,
+    GET_MASTER_ADDRESS,
+    REGISTER_LISTENER,
+    UNREGISTER_LISTENER,
+};
+
+const String16 ICommonClock::kServiceName("common_time.clock");
+const uint64_t ICommonClock::kInvalidTimelineID = 0;
+const int32_t ICommonClock::kErrorEstimateUnknown = 0x7FFFFFFF;
+
+class BpCommonClock : public BpInterface<ICommonClock>
+{
+  public:
+    BpCommonClock(const sp<IBinder>& impl)
+        : BpInterface<ICommonClock>(impl) {}
+
+    virtual status_t isCommonTimeValid(bool* valid, uint32_t* timelineID) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(IS_COMMON_TIME_VALID,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *valid = reply.readInt32();
+                *timelineID = reply.readInt32();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t commonTimeToLocalTime(int64_t commonTime,
+            int64_t* localTime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        data.writeInt64(commonTime);
+        status_t status = remote()->transact(COMMON_TIME_TO_LOCAL_TIME,
+                data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *localTime = reply.readInt64();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t localTimeToCommonTime(int64_t localTime,
+            int64_t* commonTime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        data.writeInt64(localTime);
+        status_t status = remote()->transact(LOCAL_TIME_TO_COMMON_TIME,
+                data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *commonTime = reply.readInt64();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getCommonTime(int64_t* commonTime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_COMMON_TIME, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *commonTime = reply.readInt64();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getCommonFreq(uint64_t* freq) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_COMMON_FREQ, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *freq = reply.readInt64();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getLocalTime(int64_t* localTime) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_LOCAL_TIME, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *localTime = reply.readInt64();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getLocalFreq(uint64_t* freq) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_LOCAL_FREQ, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *freq = reply.readInt64();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getEstimatedError(int32_t* estimate) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_ESTIMATED_ERROR, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *estimate = reply.readInt32();
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getTimelineID(uint64_t* id) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_TIMELINE_ID, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *id = static_cast<uint64_t>(reply.readInt64());
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getState(State* state) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_STATE, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *state = static_cast<State>(reply.readInt32());
+            }
+        }
+        return status;
+    }
+
+    virtual status_t getMasterAddr(struct sockaddr_storage* addr) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_MASTER_ADDRESS, data, &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK)
+                deserializeSockaddr(&reply, addr);
+        }
+        return status;
+    }
+
+    virtual status_t registerListener(
+            const sp<ICommonClockListener>& listener) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        data.writeStrongBinder(listener->asBinder());
+
+        status_t status = remote()->transact(REGISTER_LISTENER, data, &reply);
+
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t unregisterListener(
+            const sp<ICommonClockListener>& listener) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonClock::getInterfaceDescriptor());
+        data.writeStrongBinder(listener->asBinder());
+        status_t status = remote()->transact(UNREGISTER_LISTENER, data, &reply);
+
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CommonClock, "android.os.ICommonClock");
+
+status_t BnCommonClock::onTransact(uint32_t code,
+                                   const Parcel& data,
+                                   Parcel* reply,
+                                   uint32_t flags) {
+    switch(code) {
+        case IS_COMMON_TIME_VALID: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            bool valid;
+            uint32_t timelineID;
+            status_t status = isCommonTimeValid(&valid, &timelineID);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(valid);
+                reply->writeInt32(timelineID);
+            }
+            return OK;
+        } break;
+
+        case COMMON_TIME_TO_LOCAL_TIME: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            int64_t commonTime = data.readInt64();
+            int64_t localTime;
+            status_t status = commonTimeToLocalTime(commonTime, &localTime);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(localTime);
+            }
+            return OK;
+        } break;
+
+        case LOCAL_TIME_TO_COMMON_TIME: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            int64_t localTime = data.readInt64();
+            int64_t commonTime;
+            status_t status = localTimeToCommonTime(localTime, &commonTime);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(commonTime);
+            }
+            return OK;
+        } break;
+
+        case GET_COMMON_TIME: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            int64_t commonTime;
+            status_t status = getCommonTime(&commonTime);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(commonTime);
+            }
+            return OK;
+        } break;
+
+        case GET_COMMON_FREQ: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            uint64_t freq;
+            status_t status = getCommonFreq(&freq);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(freq);
+            }
+            return OK;
+        } break;
+
+        case GET_LOCAL_TIME: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            int64_t localTime;
+            status_t status = getLocalTime(&localTime);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(localTime);
+            }
+            return OK;
+        } break;
+
+        case GET_LOCAL_FREQ: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            uint64_t freq;
+            status_t status = getLocalFreq(&freq);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(freq);
+            }
+            return OK;
+        } break;
+
+        case GET_ESTIMATED_ERROR: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            int32_t error;
+            status_t status = getEstimatedError(&error);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(error);
+            }
+            return OK;
+        } break;
+
+        case GET_TIMELINE_ID: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            uint64_t id;
+            status_t status = getTimelineID(&id);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(static_cast<int64_t>(id));
+            }
+            return OK;
+        } break;
+
+        case GET_STATE: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            State state;
+            status_t status = getState(&state);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(static_cast<int32_t>(state));
+            }
+            return OK;
+        } break;
+
+        case GET_MASTER_ADDRESS: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            struct sockaddr_storage addr;
+            status_t status = getMasterAddr(&addr);
+
+            if ((status == OK) && !canSerializeSockaddr(&addr)) {
+                status = UNKNOWN_ERROR;
+            }
+
+            reply->writeInt32(status);
+
+            if (status == OK) {
+                serializeSockaddr(reply, &addr);
+            }
+
+            return OK;
+        } break;
+
+        case REGISTER_LISTENER: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            sp<ICommonClockListener> listener =
+                interface_cast<ICommonClockListener>(data.readStrongBinder());
+            status_t status = registerListener(listener);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case UNREGISTER_LISTENER: {
+            CHECK_INTERFACE(ICommonClock, data, reply);
+            sp<ICommonClockListener> listener =
+                interface_cast<ICommonClockListener>(data.readStrongBinder());
+            status_t status = unregisterListener(listener);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+/***** ICommonClockListener *****/
+
+enum {
+    ON_TIMELINE_CHANGED = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+class BpCommonClockListener : public BpInterface<ICommonClockListener>
+{
+  public:
+    BpCommonClockListener(const sp<IBinder>& impl)
+        : BpInterface<ICommonClockListener>(impl) {}
+
+    virtual void onTimelineChanged(uint64_t timelineID) {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                ICommonClockListener::getInterfaceDescriptor());
+        data.writeInt64(timelineID);
+        remote()->transact(ON_TIMELINE_CHANGED, data, &reply);
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CommonClockListener,
+                         "android.os.ICommonClockListener");
+
+status_t BnCommonClockListener::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+        case ON_TIMELINE_CHANGED: {
+            CHECK_INTERFACE(ICommonClockListener, data, reply);
+            uint32_t timelineID = data.readInt64();
+            onTimelineChanged(timelineID);
+            return NO_ERROR;
+        } break;
+    }
+
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+}; // namespace android
diff --git a/libs/common_time/ICommonTimeConfig.cpp b/libs/common_time/ICommonTimeConfig.cpp
new file mode 100644
index 0000000..8eb37cb
--- /dev/null
+++ b/libs/common_time/ICommonTimeConfig.cpp
@@ -0,0 +1,508 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <linux/socket.h>
+
+#include <common_time/ICommonTimeConfig.h>
+#include <binder/Parcel.h>
+
+#include "utils.h"
+
+namespace android {
+
+/***** ICommonTimeConfig *****/
+
+enum {
+    GET_MASTER_ELECTION_PRIORITY = IBinder::FIRST_CALL_TRANSACTION,
+    SET_MASTER_ELECTION_PRIORITY,
+    GET_MASTER_ELECTION_ENDPOINT,
+    SET_MASTER_ELECTION_ENDPOINT,
+    GET_MASTER_ELECTION_GROUP_ID,
+    SET_MASTER_ELECTION_GROUP_ID,
+    GET_INTERFACE_BINDING,
+    SET_INTERFACE_BINDING,
+    GET_MASTER_ANNOUNCE_INTERVAL,
+    SET_MASTER_ANNOUNCE_INTERVAL,
+    GET_CLIENT_SYNC_INTERVAL,
+    SET_CLIENT_SYNC_INTERVAL,
+    GET_PANIC_THRESHOLD,
+    SET_PANIC_THRESHOLD,
+    GET_AUTO_DISABLE,
+    SET_AUTO_DISABLE,
+    FORCE_NETWORKLESS_MASTER_MODE,
+};
+
+const String16 ICommonTimeConfig::kServiceName("common_time.config");
+
+class BpCommonTimeConfig : public BpInterface<ICommonTimeConfig>
+{
+  public:
+    BpCommonTimeConfig(const sp<IBinder>& impl)
+        : BpInterface<ICommonTimeConfig>(impl) {}
+
+    virtual status_t getMasterElectionPriority(uint8_t *priority) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_MASTER_ELECTION_PRIORITY,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *priority = static_cast<uint8_t>(reply.readInt32());
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setMasterElectionPriority(uint8_t priority) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        data.writeInt32(static_cast<int32_t>(priority));
+        status_t status = remote()->transact(SET_MASTER_ELECTION_PRIORITY,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_MASTER_ELECTION_ENDPOINT,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                deserializeSockaddr(&reply, addr);
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setMasterElectionEndpoint(
+            const struct sockaddr_storage *addr) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        if (!canSerializeSockaddr(addr))
+            return BAD_VALUE;
+        if (NULL == addr) {
+            data.writeInt32(0);
+        } else {
+            data.writeInt32(1);
+            serializeSockaddr(&data, addr);
+        }
+        status_t status = remote()->transact(SET_MASTER_ELECTION_ENDPOINT,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t getMasterElectionGroupId(uint64_t *id) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_MASTER_ELECTION_GROUP_ID,
+                                             data,
+                                             &reply);
+
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *id = static_cast<uint64_t>(reply.readInt64());
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setMasterElectionGroupId(uint64_t id) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        data.writeInt64(id);
+        status_t status = remote()->transact(SET_MASTER_ELECTION_GROUP_ID,
+                                             data,
+                                             &reply);
+
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t getInterfaceBinding(String16& ifaceName) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_INTERFACE_BINDING,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                ifaceName = reply.readString16();
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setInterfaceBinding(const String16& ifaceName) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        data.writeString16(ifaceName);
+        status_t status = remote()->transact(SET_INTERFACE_BINDING,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t getMasterAnnounceInterval(int *interval) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_MASTER_ANNOUNCE_INTERVAL,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *interval = reply.readInt32();
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setMasterAnnounceInterval(int interval) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        data.writeInt32(interval);
+        status_t status = remote()->transact(SET_MASTER_ANNOUNCE_INTERVAL,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t getClientSyncInterval(int *interval) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_CLIENT_SYNC_INTERVAL,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *interval = reply.readInt32();
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setClientSyncInterval(int interval) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        data.writeInt32(interval);
+        status_t status = remote()->transact(SET_CLIENT_SYNC_INTERVAL,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t getPanicThreshold(int *threshold) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_PANIC_THRESHOLD,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *threshold = reply.readInt32();
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setPanicThreshold(int threshold) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        data.writeInt32(threshold);
+        status_t status = remote()->transact(SET_PANIC_THRESHOLD,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t getAutoDisable(bool *autoDisable) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(GET_AUTO_DISABLE,
+                                             data,
+                                             &reply);
+        if (status == OK) {
+            status = reply.readInt32();
+            if (status == OK) {
+                *autoDisable = (0 != reply.readInt32());
+            }
+        }
+
+        return status;
+    }
+
+    virtual status_t setAutoDisable(bool autoDisable) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        data.writeInt32(autoDisable ? 1 : 0);
+        status_t status = remote()->transact(SET_AUTO_DISABLE,
+                                             data,
+                                             &reply);
+
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+
+    virtual status_t forceNetworklessMasterMode() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ICommonTimeConfig::getInterfaceDescriptor());
+        status_t status = remote()->transact(FORCE_NETWORKLESS_MASTER_MODE,
+                                             data,
+                                             &reply);
+
+        if (status == OK) {
+            status = reply.readInt32();
+        }
+
+        return status;
+    }
+};
+
+IMPLEMENT_META_INTERFACE(CommonTimeConfig, "android.os.ICommonTimeConfig");
+
+status_t BnCommonTimeConfig::onTransact(uint32_t code,
+                                   const Parcel& data,
+                                   Parcel* reply,
+                                   uint32_t flags) {
+    switch(code) {
+        case GET_MASTER_ELECTION_PRIORITY: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            uint8_t priority;
+            status_t status = getMasterElectionPriority(&priority);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(static_cast<int32_t>(priority));
+            }
+            return OK;
+        } break;
+
+        case SET_MASTER_ELECTION_PRIORITY: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            uint8_t priority = static_cast<uint8_t>(data.readInt32());
+            status_t status = setMasterElectionPriority(priority);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case GET_MASTER_ELECTION_ENDPOINT: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            struct sockaddr_storage addr;
+            status_t status = getMasterElectionEndpoint(&addr);
+
+            if ((status == OK) && !canSerializeSockaddr(&addr)) {
+                status = UNKNOWN_ERROR;
+            }
+
+            reply->writeInt32(status);
+
+            if (status == OK) {
+                serializeSockaddr(reply, &addr);
+            }
+
+            return OK;
+        } break;
+
+        case SET_MASTER_ELECTION_ENDPOINT: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            struct sockaddr_storage addr;
+            int hasAddr = data.readInt32();
+
+            status_t status;
+            if (hasAddr) {
+                deserializeSockaddr(&data, &addr);
+                status = setMasterElectionEndpoint(&addr);
+            } else {
+                status = setMasterElectionEndpoint(&addr);
+            }
+
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case GET_MASTER_ELECTION_GROUP_ID: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            uint64_t id;
+            status_t status = getMasterElectionGroupId(&id);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt64(id);
+            }
+            return OK;
+        } break;
+
+        case SET_MASTER_ELECTION_GROUP_ID: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            uint64_t id = static_cast<uint64_t>(data.readInt64());
+            status_t status = setMasterElectionGroupId(id);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case GET_INTERFACE_BINDING: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            String16 ret;
+            status_t status = getInterfaceBinding(ret);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeString16(ret);
+            }
+            return OK;
+        } break;
+
+        case SET_INTERFACE_BINDING: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            String16 ifaceName;
+            ifaceName = data.readString16();
+            status_t status = setInterfaceBinding(ifaceName);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case GET_MASTER_ANNOUNCE_INTERVAL: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            int interval;
+            status_t status = getMasterAnnounceInterval(&interval);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(interval);
+            }
+            return OK;
+        } break;
+
+        case SET_MASTER_ANNOUNCE_INTERVAL: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            int interval = data.readInt32();
+            status_t status = setMasterAnnounceInterval(interval);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case GET_CLIENT_SYNC_INTERVAL: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            int interval;
+            status_t status = getClientSyncInterval(&interval);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(interval);
+            }
+            return OK;
+        } break;
+
+        case SET_CLIENT_SYNC_INTERVAL: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            int interval = data.readInt32();
+            status_t status = setClientSyncInterval(interval);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case GET_PANIC_THRESHOLD: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            int threshold;
+            status_t status = getPanicThreshold(&threshold);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(threshold);
+            }
+            return OK;
+        } break;
+
+        case SET_PANIC_THRESHOLD: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            int threshold = data.readInt32();
+            status_t status = setPanicThreshold(threshold);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case GET_AUTO_DISABLE: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            bool autoDisable;
+            status_t status = getAutoDisable(&autoDisable);
+            reply->writeInt32(status);
+            if (status == OK) {
+                reply->writeInt32(autoDisable ? 1 : 0);
+            }
+            return OK;
+        } break;
+
+        case SET_AUTO_DISABLE: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            bool autoDisable = (0 != data.readInt32());
+            status_t status = setAutoDisable(autoDisable);
+            reply->writeInt32(status);
+            return OK;
+        } break;
+
+        case FORCE_NETWORKLESS_MASTER_MODE: {
+            CHECK_INTERFACE(ICommonTimeConfig, data, reply);
+            status_t status = forceNetworklessMasterMode();
+            reply->writeInt32(status);
+            return OK;
+        } break;
+    }
+    return BBinder::onTransact(code, data, reply, flags);
+}
+
+}; // namespace android
+
diff --git a/libs/common_time/cc_helper.cpp b/libs/common_time/cc_helper.cpp
new file mode 100644
index 0000000..8d8556c
--- /dev/null
+++ b/libs/common_time/cc_helper.cpp
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include <common_time/cc_helper.h>
+#include <common_time/ICommonClock.h>
+#include <utils/threads.h>
+
+namespace android {
+
+Mutex CCHelper::lock_;
+sp<ICommonClock> CCHelper::common_clock_;
+sp<ICommonClockListener> CCHelper::common_clock_listener_;
+uint32_t CCHelper::ref_count_ = 0;
+
+bool CCHelper::verifyClock_l() {
+    bool ret = false;
+
+    if (common_clock_ == NULL) {
+        common_clock_ = ICommonClock::getInstance();
+        if (common_clock_ == NULL)
+            goto bailout;
+    }
+
+    if (ref_count_ > 0) {
+        if (common_clock_listener_ == NULL) {
+            common_clock_listener_ = new CommonClockListener();
+            if (common_clock_listener_ == NULL)
+                goto bailout;
+
+            if (OK != common_clock_->registerListener(common_clock_listener_))
+                goto bailout;
+        }
+    }
+
+    ret = true;
+
+bailout:
+    if (!ret) {
+        common_clock_listener_ = NULL;
+        common_clock_ = NULL;
+    }
+    return ret;
+}
+
+CCHelper::CCHelper() {
+    Mutex::Autolock lock(&lock_);
+    ref_count_++;
+    verifyClock_l();
+}
+
+CCHelper::~CCHelper() {
+    Mutex::Autolock lock(&lock_);
+
+    assert(ref_count_ > 0);
+    ref_count_--;
+
+    // If we were the last CCHelper instance in the system, and we had
+    // previously register a listener, unregister it now so that the common time
+    // service has the chance to go into auto-disabled mode.
+    if (!ref_count_ &&
+       (common_clock_ != NULL) &&
+       (common_clock_listener_ != NULL)) {
+        common_clock_->unregisterListener(common_clock_listener_);
+        common_clock_listener_ = NULL;
+    }
+}
+
+void CCHelper::CommonClockListener::onTimelineChanged(uint64_t timelineID) {
+    // do nothing; listener is only really used as a token so the server can
+    // find out when clients die.
+}
+
+// Helper methods which attempts to make calls to the common time binder
+// service.  If the first attempt fails with DEAD_OBJECT, the helpers will
+// attempt to make a connection to the service again (assuming that the process
+// hosting the service had crashed and the client proxy we are holding is dead)
+// If the second attempt fails, or no connection can be made, the we let the
+// error propagate up the stack and let the caller deal with the situation as
+// best they can.
+#define CCHELPER_METHOD(decl, call)                 \
+    status_t CCHelper::decl {                       \
+        Mutex::Autolock lock(&lock_);               \
+                                                    \
+        if (!verifyClock_l())                       \
+            return DEAD_OBJECT;                     \
+                                                    \
+        status_t status = common_clock_->call;      \
+        if (DEAD_OBJECT == status) {                \
+            if (!verifyClock_l())                   \
+                return DEAD_OBJECT;                 \
+            status = common_clock_->call;           \
+        }                                           \
+                                                    \
+        return status;                              \
+    }
+
+#define VERIFY_CLOCK()
+
+CCHELPER_METHOD(isCommonTimeValid(bool* valid, uint32_t* timelineID),
+                isCommonTimeValid(valid, timelineID))
+CCHELPER_METHOD(commonTimeToLocalTime(int64_t commonTime, int64_t* localTime),
+                commonTimeToLocalTime(commonTime, localTime))
+CCHELPER_METHOD(localTimeToCommonTime(int64_t localTime, int64_t* commonTime),
+                localTimeToCommonTime(localTime, commonTime))
+CCHELPER_METHOD(getCommonTime(int64_t* commonTime),
+                getCommonTime(commonTime))
+CCHELPER_METHOD(getCommonFreq(uint64_t* freq),
+                getCommonFreq(freq))
+CCHELPER_METHOD(getLocalTime(int64_t* localTime),
+                getLocalTime(localTime))
+CCHELPER_METHOD(getLocalFreq(uint64_t* freq),
+                getLocalFreq(freq))
+
+}  // namespace android
diff --git a/libs/common_time/local_clock.cpp b/libs/common_time/local_clock.cpp
new file mode 100644
index 0000000..a7c61fc
--- /dev/null
+++ b/libs/common_time/local_clock.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <common_time/local_clock.h>
+#include <hardware/hardware.h>
+#include <hardware/local_time_hal.h>
+#include <utils/Errors.h>
+#include <utils/threads.h>
+
+namespace android {
+
+Mutex LocalClock::dev_lock_;
+local_time_hw_device_t* LocalClock::dev_ = NULL;
+
+LocalClock::LocalClock() {
+    int res;
+    const hw_module_t* mod;
+
+    AutoMutex lock(&dev_lock_);
+
+    if (dev_ != NULL)
+        return;
+
+    res = hw_get_module_by_class(LOCAL_TIME_HARDWARE_MODULE_ID, NULL, &mod);
+    if (res) {
+        ALOGE("Failed to open local time HAL module (res = %d)", res);
+    } else {
+        res = local_time_hw_device_open(mod, &dev_);
+        if (res) {
+            ALOGE("Failed to open local time HAL device (res = %d)", res);
+            dev_ = NULL;
+        }
+    }
+}
+
+bool LocalClock::initCheck() {
+    return (NULL != dev_);
+}
+
+int64_t LocalClock::getLocalTime() {
+    assert(NULL != dev_);
+    assert(NULL != dev_->get_local_time);
+
+    return dev_->get_local_time(dev_);
+}
+
+uint64_t LocalClock::getLocalFreq() {
+    assert(NULL != dev_);
+    assert(NULL != dev_->get_local_freq);
+
+    return dev_->get_local_freq(dev_);
+}
+
+status_t LocalClock::setLocalSlew(int16_t rate) {
+    assert(NULL != dev_);
+
+    if (!dev_->set_local_slew)
+        return INVALID_OPERATION;
+
+    return static_cast<status_t>(dev_->set_local_slew(dev_, rate));
+}
+
+int32_t LocalClock::getDebugLog(struct local_time_debug_event* records,
+                                int max_records) {
+    assert(NULL != dev_);
+
+    if (!dev_->get_debug_log)
+        return INVALID_OPERATION;
+
+    return dev_->get_debug_log(dev_, records, max_records);
+}
+
+}  // namespace android
diff --git a/libs/common_time/utils.cpp b/libs/common_time/utils.cpp
new file mode 100644
index 0000000..6539171
--- /dev/null
+++ b/libs/common_time/utils.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <arpa/inet.h>
+#include <linux/socket.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+bool canSerializeSockaddr(const struct sockaddr_storage* addr) {
+    switch (addr->ss_family) {
+        case AF_INET:
+        case AF_INET6:
+            return true;
+        default:
+            return false;
+    }
+}
+
+void serializeSockaddr(Parcel* p, const struct sockaddr_storage* addr) {
+    switch (addr->ss_family) {
+        case AF_INET: {
+            const struct sockaddr_in* s =
+                reinterpret_cast<const struct sockaddr_in*>(addr);
+            p->writeInt32(AF_INET);
+            p->writeInt32(ntohl(s->sin_addr.s_addr));
+            p->writeInt32(static_cast<int32_t>(ntohs(s->sin_port)));
+        } break;
+
+        case AF_INET6: {
+            const struct sockaddr_in6* s =
+                reinterpret_cast<const struct sockaddr_in6*>(addr);
+            const int32_t* a =
+                reinterpret_cast<const int32_t*>(s->sin6_addr.s6_addr);
+            p->writeInt32(AF_INET6);
+            p->writeInt32(ntohl(a[0]));
+            p->writeInt32(ntohl(a[1]));
+            p->writeInt32(ntohl(a[2]));
+            p->writeInt32(ntohl(a[3]));
+            p->writeInt32(static_cast<int32_t>(ntohs(s->sin6_port)));
+            p->writeInt32(ntohl(s->sin6_flowinfo));
+            p->writeInt32(ntohl(s->sin6_scope_id));
+        } break;
+    }
+}
+
+void deserializeSockaddr(const Parcel* p, struct sockaddr_storage* addr) {
+    memset(addr, 0, sizeof(addr));
+
+    addr->ss_family = p->readInt32();
+    switch(addr->ss_family) {
+        case AF_INET: {
+            struct sockaddr_in* s =
+                reinterpret_cast<struct sockaddr_in*>(addr);
+            s->sin_addr.s_addr = htonl(p->readInt32());
+            s->sin_port = htons(static_cast<uint16_t>(p->readInt32()));
+        } break;
+
+        case AF_INET6: {
+            struct sockaddr_in6* s =
+                reinterpret_cast<struct sockaddr_in6*>(addr);
+            int32_t* a = reinterpret_cast<int32_t*>(s->sin6_addr.s6_addr);
+
+            a[0] = htonl(p->readInt32());
+            a[1] = htonl(p->readInt32());
+            a[2] = htonl(p->readInt32());
+            a[3] = htonl(p->readInt32());
+            s->sin6_port = htons(static_cast<uint16_t>(p->readInt32()));
+            s->sin6_flowinfo = htonl(p->readInt32());
+            s->sin6_scope_id = htonl(p->readInt32());
+        } break;
+    }
+}
+
+}  // namespace android
diff --git a/libs/common_time/utils.h b/libs/common_time/utils.h
new file mode 100644
index 0000000..ce79d0d
--- /dev/null
+++ b/libs/common_time/utils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_LIBCOMMONCLOCK_UTILS_H
+#define ANDROID_LIBCOMMONCLOCK_UTILS_H
+
+#include <linux/socket.h>
+
+#include <binder/Parcel.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+extern bool canSerializeSockaddr(const struct sockaddr_storage* addr);
+extern void serializeSockaddr(Parcel* p, const struct sockaddr_storage* addr);
+extern status_t deserializeSockaddr(const Parcel* p,
+                                    struct sockaddr_storage* addr);
+
+};  // namespace android
+
+#endif  // ANDROID_LIBCOMMONCLOCK_UTILS_H
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 1a11fbc..f9088ac 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -226,6 +226,11 @@
 
     while (!mReader.eof()) {
         int op = mReader.readInt();
+        if (op & OP_MAY_BE_SKIPPED_MASK) {
+            int skip = mReader.readInt();
+            ALOGD("%sSkip %d", (char*) indent, skip);
+            op &= ~OP_MAY_BE_SKIPPED_MASK;
+       }
 
         switch (op) {
             case DrawGLFunction: {
@@ -316,8 +321,9 @@
                 DisplayList* displayList = getDisplayList();
                 uint32_t width = getUInt();
                 uint32_t height = getUInt();
-                ALOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
-                    displayList, width, height, level + 1);
+                int32_t flags = getInt();
+                ALOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
+                    displayList, width, height, flags, level + 1);
                 renderer.outputDisplayList(displayList, level + 1);
             }
             break;
@@ -551,7 +557,7 @@
  * in the output() function, since that function processes the same list of opcodes for the
  * purposes of logging display list info for a given view.
  */
-bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level) {
+bool DisplayList::replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level) {
     bool needsInvalidate = false;
     TextContainer text;
     mReader.rewind();
@@ -572,6 +578,18 @@
     int saveCount = renderer.getSaveCount() - 1;
     while (!mReader.eof()) {
         int op = mReader.readInt();
+        if (op & OP_MAY_BE_SKIPPED_MASK) {
+            int32_t skip = mReader.readInt() * 4;
+            if (CC_LIKELY(flags & kReplayFlag_ClipChildren)) {
+                mReader.skip(skip);
+                DISPLAY_LIST_LOGD("%s%s skipping %d bytes", (char*) indent,
+                        OP_NAMES[op & ~OP_MAY_BE_SKIPPED_MASK], skip);
+                continue;
+            } else {
+                op &= ~OP_MAY_BE_SKIPPED_MASK;
+                ALOGD("%s", OP_NAMES[op]);
+            }
+        }
         logBuffer.writeCommand(level, op);
 
         switch (op) {
@@ -584,7 +602,7 @@
             }
             break;
             case Save: {
-                int rendererNum = getInt();
+                int32_t rendererNum = getInt();
                 DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], rendererNum);
                 renderer.save(rendererNum);
             }
@@ -595,7 +613,7 @@
             }
             break;
             case RestoreToCount: {
-                int restoreCount = saveCount + getInt();
+                int32_t restoreCount = saveCount + getInt();
                 DISPLAY_LIST_LOGD("%s%s %d", (char*) indent, OP_NAMES[op], restoreCount);
                 renderer.restoreToCount(restoreCount);
             }
@@ -606,7 +624,7 @@
                 float f3 = getFloat();
                 float f4 = getFloat();
                 SkPaint* paint = getPaint(renderer);
-                int flags = getInt();
+                int32_t flags = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %p, 0x%x", (char*) indent,
                     OP_NAMES[op], f1, f2, f3, f4, paint, flags);
                 renderer.saveLayer(f1, f2, f3, f4, paint, flags);
@@ -617,8 +635,8 @@
                 float f2 = getFloat();
                 float f3 = getFloat();
                 float f4 = getFloat();
-                int alpha = getInt();
-                int flags = getInt();
+                int32_t alpha = getInt();
+                int32_t flags = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d, 0x%x", (char*) indent,
                     OP_NAMES[op], f1, f2, f3, f4, alpha, flags);
                 renderer.saveLayerAlpha(f1, f2, f3, f4, alpha, flags);
@@ -668,7 +686,7 @@
                 float f2 = getFloat();
                 float f3 = getFloat();
                 float f4 = getFloat();
-                int regionOp = getInt();
+                int32_t regionOp = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %d", (char*) indent, OP_NAMES[op],
                     f1, f2, f3, f4, regionOp);
                 renderer.clipRect(f1, f2, f3, f4, (SkRegion::Op) regionOp);
@@ -678,10 +696,11 @@
                 DisplayList* displayList = getDisplayList();
                 uint32_t width = getUInt();
                 uint32_t height = getUInt();
-                DISPLAY_LIST_LOGD("%s%s %p, %dx%d, %d", (char*) indent, OP_NAMES[op],
-                    displayList, width, height, level + 1);
+                int32_t flags = getInt();
+                DISPLAY_LIST_LOGD("%s%s %p, %dx%d, 0x%x %d", (char*) indent, OP_NAMES[op],
+                    displayList, width, height, flags, level + 1);
                 needsInvalidate |= renderer.drawDisplayList(displayList, width, height,
-                        dirty, level + 1);
+                        dirty, flags, level + 1);
             }
             break;
             case DrawLayer: {
@@ -730,7 +749,7 @@
             }
             break;
             case DrawBitmapMesh: {
-                int verticesCount = 0;
+                int32_t verticesCount = 0;
                 uint32_t colorsCount = 0;
 
                 SkBitmap* bitmap = getBitmap();
@@ -738,7 +757,7 @@
                 uint32_t meshHeight = getInt();
                 float* vertices = getFloats(verticesCount);
                 bool hasColors = getInt();
-                int* colors = hasColors ? getInts(colorsCount) : NULL;
+                int32_t* colors = hasColors ? getInts(colorsCount) : NULL;
                 SkPaint* paint = getPaint(renderer);
 
                 DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -771,8 +790,8 @@
             }
             break;
             case DrawColor: {
-                int color = getInt();
-                int xferMode = getInt();
+                int32_t color = getInt();
+                int32_t xferMode = getInt();
                 DISPLAY_LIST_LOGD("%s%s 0x%x %d", (char*) indent, OP_NAMES[op], color, xferMode);
                 renderer.drawColor(color, (SkXfermode::Mode) xferMode);
             }
@@ -829,7 +848,7 @@
                 float f4 = getFloat();
                 float f5 = getFloat();
                 float f6 = getFloat();
-                int i1 = getInt();
+                int32_t i1 = getInt();
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, %.2f, %.2f, %.2f, %d, %p",
                     (char*) indent, OP_NAMES[op], f1, f2, f3, f4, f5, f6, i1, paint);
@@ -844,7 +863,7 @@
             }
             break;
             case DrawLines: {
-                int count = 0;
+                int32_t count = 0;
                 float* points = getFloats(count);
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -852,7 +871,7 @@
             }
             break;
             case DrawPoints: {
-                int count = 0;
+                int32_t count = 0;
                 float* points = getFloats(count);
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s", (char*) indent, OP_NAMES[op]);
@@ -861,7 +880,7 @@
             break;
             case DrawText: {
                 getText(&text);
-                int count = getInt();
+                int32_t count = getInt();
                 float x = getFloat();
                 float y = getFloat();
                 SkPaint* paint = getPaint(renderer);
@@ -873,8 +892,8 @@
             break;
             case DrawPosText: {
                 getText(&text);
-                int count = getInt();
-                int positionsCount = 0;
+                int32_t count = getInt();
+                int32_t positionsCount = 0;
                 float* positions = getFloats(positionsCount);
                 SkPaint* paint = getPaint(renderer);
                 DISPLAY_LIST_LOGD("%s%s %s, %d, %d, %p", (char*) indent,
@@ -913,7 +932,7 @@
                 float radius = getFloat();
                 float dx = getFloat();
                 float dy = getFloat();
-                int color = getInt();
+                int32_t color = getInt();
                 DISPLAY_LIST_LOGD("%s%s %.2f, %.2f, %.2f, 0x%x", (char*) indent, OP_NAMES[op],
                     radius, dx, dy, color);
                 renderer.setupShadow(radius, dx, dy, color);
@@ -925,8 +944,8 @@
             }
             break;
             case SetupPaintFilter: {
-                int clearBits = getInt();
-                int setBits = getInt();
+                int32_t clearBits = getInt();
+                int32_t setBits = getInt();
                 DISPLAY_LIST_LOGD("%s%s 0x%x, 0x%x", (char*) indent, OP_NAMES[op],
                         clearBits, setBits);
                 renderer.setupPaintFilter(clearBits, setBits);
@@ -949,7 +968,8 @@
 // Base structure
 ///////////////////////////////////////////////////////////////////////////////
 
-DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE), mHasDrawOps(false) {
+DisplayListRenderer::DisplayListRenderer(): mWriter(MIN_WRITER_SIZE),
+        mTranslateX(0.0f), mTranslateY(0.0f), mHasTranslate(false), mHasDrawOps(false) {
 }
 
 DisplayListRenderer::~DisplayListRenderer() {
@@ -1019,6 +1039,7 @@
 
 void DisplayListRenderer::finish() {
     insertRestoreToCount();
+    insertTranlate();
     OpenGLRenderer::finish();
 }
 
@@ -1043,15 +1064,18 @@
 
 void DisplayListRenderer::restore() {
     if (mRestoreSaveCount < 0) {
-        addOp(DisplayList::Restore);
-    } else {
-        mRestoreSaveCount--;
+        restoreToCount(getSaveCount() - 1);
+        return;
     }
+
+    mRestoreSaveCount--;
+    insertTranlate();
     OpenGLRenderer::restore();
 }
 
 void DisplayListRenderer::restoreToCount(int saveCount) {
     mRestoreSaveCount = saveCount;
+    insertTranlate();
     OpenGLRenderer::restoreToCount(saveCount);
 }
 
@@ -1074,8 +1098,10 @@
 }
 
 void DisplayListRenderer::translate(float dx, float dy) {
-    addOp(DisplayList::Translate);
-    addPoint(dx, dy);
+    mHasTranslate = true;
+    mTranslateX += dx;
+    mTranslateY += dy;
+    insertRestoreToCount();
     OpenGLRenderer::translate(dx, dy);
 }
 
@@ -1118,12 +1144,15 @@
 }
 
 bool DisplayListRenderer::drawDisplayList(DisplayList* displayList,
-        uint32_t width, uint32_t height, Rect& dirty, uint32_t level) {
+        uint32_t width, uint32_t height, Rect& dirty, int32_t flags, uint32_t level) {
     // dirty is an out parameter and should not be recorded,
     // it matters only when replaying the display list
-    addOp(DisplayList::DrawDisplayList);
+    const bool reject = quickReject(0.0f, 0.0f, width, height);
+    uint32_t* location = addOp(DisplayList::DrawDisplayList, reject);
     addDisplayList(displayList);
     addSize(width, height);
+    addInt(flags);
+    addSkip(location);
     return false;
 }
 
@@ -1134,30 +1163,38 @@
     addPaint(paint);
 }
 
-void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
-        SkPaint* paint) {
-    addOp(DisplayList::DrawBitmap);
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint) {
+    const bool reject = quickReject(left, top, left + bitmap->width(), top + bitmap->height());
+    uint32_t* location = addOp(DisplayList::DrawBitmap, reject);
     addBitmap(bitmap);
     addPoint(left, top);
     addPaint(paint);
+    addSkip(location);
 }
 
-void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix,
-        SkPaint* paint) {
-    addOp(DisplayList::DrawBitmapMatrix);
+void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint) {
+    Rect r(0.0f, 0.0f, bitmap->width(), bitmap->height());
+    const mat4 transform(*matrix);
+    transform.mapRect(r);
+
+    const bool reject = quickReject(r.left, r.top, r.right, r.bottom);
+    uint32_t* location = addOp(DisplayList::DrawBitmapMatrix, reject);
     addBitmap(bitmap);
     addMatrix(matrix);
     addPaint(paint);
+    addSkip(location);
 }
 
 void DisplayListRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop,
         float dstRight, float dstBottom, SkPaint* paint) {
-    addOp(DisplayList::DrawBitmapRect);
+    const bool reject = quickReject(dstLeft, dstTop, dstRight, dstBottom);
+    uint32_t* location = addOp(DisplayList::DrawBitmapRect, reject);
     addBitmap(bitmap);
     addBounds(srcLeft, srcTop, srcRight, srcBottom);
     addBounds(dstLeft, dstTop, dstRight, dstBottom);
     addPaint(paint);
+    addSkip(location);
 }
 
 void DisplayListRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
@@ -1179,13 +1216,15 @@
 void DisplayListRenderer::drawPatch(SkBitmap* bitmap, const int32_t* xDivs, const int32_t* yDivs,
         const uint32_t* colors, uint32_t width, uint32_t height, int8_t numColors,
         float left, float top, float right, float bottom, SkPaint* paint) {
-    addOp(DisplayList::DrawPatch);
+    const bool reject = quickReject(left, top, right, bottom);
+    uint32_t* location = addOp(DisplayList::DrawPatch, reject);
     addBitmap(bitmap);
     addInts(xDivs, width);
     addInts(yDivs, height);
     addUInts(colors, numColors);
     addBounds(left, top, right, bottom);
     addPaint(paint);
+    addSkip(location);
 }
 
 void DisplayListRenderer::drawColor(int color, SkXfermode::Mode mode) {
@@ -1196,17 +1235,23 @@
 
 void DisplayListRenderer::drawRect(float left, float top, float right, float bottom,
         SkPaint* paint) {
-    addOp(DisplayList::DrawRect);
+    const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
+            quickReject(left, top, right, bottom);
+    uint32_t* location = addOp(DisplayList::DrawRect, reject);
     addBounds(left, top, right, bottom);
     addPaint(paint);
+    addSkip(location);
 }
 
 void DisplayListRenderer::drawRoundRect(float left, float top, float right, float bottom,
             float rx, float ry, SkPaint* paint) {
-    addOp(DisplayList::DrawRoundRect);
+    const bool reject = paint->getStyle() == SkPaint::kFill_Style &&
+            quickReject(left, top, right, bottom);
+    uint32_t* location = addOp(DisplayList::DrawRoundRect, reject);
     addBounds(left, top, right, bottom);
     addPoint(rx, ry);
     addPaint(paint);
+    addSkip(location);
 }
 
 void DisplayListRenderer::drawCircle(float x, float y, float radius, SkPaint* paint) {
@@ -1233,9 +1278,15 @@
 }
 
 void DisplayListRenderer::drawPath(SkPath* path, SkPaint* paint) {
-    addOp(DisplayList::DrawPath);
+    float left, top, offset;
+    uint32_t width, height;
+    computePathBounds(path, paint, left, top, offset, width, height);
+
+    const bool reject = quickReject(left - offset, top - offset, width, height);
+    uint32_t* location = addOp(DisplayList::DrawPath, reject);
     addPath(path);
     addPaint(paint);
+    addSkip(location);
 }
 
 void DisplayListRenderer::drawLines(float* points, int count, SkPaint* paint) {
@@ -1252,11 +1303,8 @@
 
 void DisplayListRenderer::drawText(const char* text, int bytesCount, int count,
         float x, float y, SkPaint* paint, float length) {
-    if (count <= 0) return;
-    addOp(DisplayList::DrawText);
-    addText(text, bytesCount);
-    addInt(count);
-    addPoint(x, y);
+    if (!text || count <= 0) return;
+
     // TODO: We should probably make a copy of the paint instead of modifying
     //       it; modifying the paint will change its generationID the first
     //       time, which might impact caches. More investigation needed to
@@ -1265,13 +1313,27 @@
     //       its own copy as it does right now.
     // Beware: this needs Glyph encoding (already done on the Paint constructor)
     paint->setAntiAlias(true);
+    if (length < 0.0f) length = paint->measureText(text, bytesCount);
+
+    bool reject = false;
+    if (CC_LIKELY(paint->getTextAlign() == SkPaint::kLeft_Align)) {
+        SkPaint::FontMetrics metrics;
+        paint->getFontMetrics(&metrics, 0.0f);
+        reject = quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom);
+    }
+
+    uint32_t* location = addOp(DisplayList::DrawText, reject);
+    addText(text, bytesCount);
+    addInt(count);
+    addPoint(x, y);
     addPaint(paint);
-    addFloat(length < 0.0f ? paint->measureText(text, bytesCount) : length);
+    addFloat(length);
+    addSkip(location);
 }
 
 void DisplayListRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
-    if (count <= 0) return;
+    if (!text || count <= 0) return;
     addOp(DisplayList::DrawPosText);
     addText(text, bytesCount);
     addInt(count);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 46506e4..90a7145 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -42,6 +42,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 #define MIN_WRITER_SIZE 4096
+#define OP_MAY_BE_SKIPPED_MASK 0xff000000
 
 // Debug
 #if DEBUG_DISPLAY_LIST
@@ -110,13 +111,18 @@
         DrawGLFunction,
     };
 
+    // See flags defined in DisplayList.java
+    enum ReplayFlag {
+        kReplayFlag_ClipChildren = 0x1
+    };
+
     static const char* OP_NAMES[];
 
     void initFromDisplayListRenderer(const DisplayListRenderer& recorder, bool reusing = false);
 
     ANDROID_API size_t getSize();
 
-    bool replay(OpenGLRenderer& renderer, Rect& dirty, uint32_t level = 0);
+    bool replay(OpenGLRenderer& renderer, Rect& dirty, int32_t flags, uint32_t level = 0);
 
     void output(OpenGLRenderer& renderer, uint32_t level = 0);
 
@@ -167,11 +173,11 @@
         return (SkiaColorFilter*) getInt();
     }
 
-    inline int getIndex() {
+    inline int32_t getIndex() {
         return mReader.readInt();
     }
 
-    inline int getInt() {
+    inline int32_t getInt() {
         return mReader.readInt();
     }
 
@@ -209,7 +215,7 @@
         return (uint32_t*) mReader.skip(count * sizeof(uint32_t));
     }
 
-    float* getFloats(int& count) {
+    float* getFloats(int32_t& count) {
         count = getInt();
         return (float*) mReader.skip(count * sizeof(float));
     }
@@ -279,7 +285,7 @@
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
     virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
-            Rect& dirty, uint32_t level = 0);
+            Rect& dirty, int32_t flags, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
@@ -358,13 +364,45 @@
         }
     }
 
-    inline void addOp(DisplayList::Op drawOp) {
+    void insertTranlate() {
+        if (mHasTranslate) {
+            if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
+                mWriter.writeInt(DisplayList::Translate);
+                addPoint(mTranslateX, mTranslateY);
+                mTranslateX = mTranslateY = 0.0f;
+            }
+            mHasTranslate = false;
+        }
+    }
+
+    inline void addOp(const DisplayList::Op drawOp) {
         insertRestoreToCount();
+        insertTranlate();
         mWriter.writeInt(drawOp);
         mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
     }
 
-    inline void addInt(int value) {
+    uint32_t* addOp(const DisplayList::Op drawOp, const bool reject) {
+        insertRestoreToCount();
+        insertTranlate();
+        mHasDrawOps = mHasDrawOps || drawOp >= DisplayList::DrawDisplayList;
+        if (reject) {
+            mWriter.writeInt(OP_MAY_BE_SKIPPED_MASK | drawOp);
+            mWriter.writeInt(0);
+            uint32_t* location = reject ? mWriter.peek32(mWriter.size() - 4) : NULL;
+            return location;
+        }
+        mWriter.writeInt(drawOp);
+        return NULL;
+    }
+
+    inline void addSkip(uint32_t* location) {
+        if (location) {
+            *location = (int32_t) (mWriter.peek32(mWriter.size() - 4) - location);
+        }
+    }
+
+    inline void addInt(int32_t value) {
         mWriter.writeInt(value);
     }
 
@@ -391,9 +429,9 @@
         mWriter.writeScalar(value);
     }
 
-    void addFloats(const float* values, int count) {
+    void addFloats(const float* values, int32_t count) {
         mWriter.writeInt(count);
-        for (int i = 0; i < count; i++) {
+        for (int32_t i = 0; i < count; i++) {
             mWriter.writeScalar(values[i]);
         }
     }
@@ -424,7 +462,8 @@
         SkPath* pathCopy = mPathMap.valueFor(path);
         if (pathCopy == NULL || pathCopy->getGenerationID() != path->getGenerationID()) {
             pathCopy = new SkPath(*path);
-            mPathMap.add(path, pathCopy);
+            // replaceValueFor() performs an add if the entry doesn't exist
+            mPathMap.replaceValueFor(path, pathCopy);
             mPaths.add(pathCopy);
         }
 
@@ -440,7 +479,8 @@
         SkPaint* paintCopy = mPaintMap.valueFor(paint);
         if (paintCopy == NULL || paintCopy->getGenerationID() != paint->getGenerationID()) {
             paintCopy = new SkPaint(*paint);
-            mPaintMap.add(paint, paintCopy);
+            // replaceValueFor() performs an add if the entry doesn't exist
+            mPaintMap.replaceValueFor(paint, paintCopy);
             mPaints.add(paintCopy);
         }
 
@@ -482,7 +522,8 @@
         // TODO: We also need to handle generation ID changes in compose shaders
         if (shaderCopy == NULL || shaderCopy->getGenerationId() != shader->getGenerationId()) {
             shaderCopy = shader->copy();
-            mShaderMap.add(shader, shaderCopy);
+            // replaceValueFor() performs an add if the entry doesn't exist
+            mShaderMap.replaceValueFor(shader, shaderCopy);
             mShaders.add(shaderCopy);
             Caches::getInstance().resourceCache.incrementRefcount(shaderCopy);
         }
@@ -513,6 +554,11 @@
     SkWriter32 mWriter;
 
     int mRestoreSaveCount;
+
+    float mTranslateX;
+    float mTranslateY;
+    bool mHasTranslate;
+
     bool mHasDrawOps;
 
     friend class DisplayList;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index afae70f..55e2ca5 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1321,7 +1321,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool OpenGLRenderer::drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
-        Rect& dirty, uint32_t level) {
+        Rect& dirty, int32_t flags, uint32_t level) {
     if (quickReject(0.0f, 0.0f, width, height)) {
         return false;
     }
@@ -1329,7 +1329,7 @@
     // All the usual checks and setup operations (quickReject, setupDraw, etc.)
     // will be performed by the display list itself
     if (displayList && displayList->isRenderable()) {
-        return displayList->replay(*this, dirty, level);
+        return displayList->replay(*this, dirty, flags, level);
     }
 
     return false;
@@ -2189,8 +2189,7 @@
     SkPaint::FontMetrics metrics;
     paint->getFontMetrics(&metrics, 0.0f);
     // If no length was specified, just perform the hit test on the Y axis
-    if (quickReject(x, y + metrics.fTop,
-            x + (length >= 0.0f ? length : INT_MAX / 2), y + metrics.fBottom)) {
+    if (quickReject(x, y + metrics.fTop, x + length, y + metrics.fBottom)) {
         return;
     }
 
@@ -2298,6 +2297,7 @@
 
     mCaches.activeTexture(0);
 
+    // TODO: Perform early clip test before we rasterize the path
     const PathTexture* texture = mCaches.pathCache.get(path, paint);
     if (!texture) return;
     const AutoTexture autoCleanup(texture);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3c2d09e..3f63c3fe 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -98,7 +98,7 @@
     virtual bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
     virtual bool drawDisplayList(DisplayList* displayList, uint32_t width, uint32_t height,
-            Rect& dirty, uint32_t level = 0);
+            Rect& dirty, int32_t flags, uint32_t level = 0);
     virtual void outputDisplayList(DisplayList* displayList, uint32_t level = 0);
     virtual void drawLayer(Layer* layer, float x, float y, SkPaint* paint);
     virtual void drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index e893f7a9..e09c243 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -24,6 +24,23 @@
 namespace android {
 namespace uirenderer {
 
+// Defined in ShapeCache.h
+void computePathBounds(const SkPath *path, const SkPaint* paint,
+        float& left, float& top, float& offset, uint32_t& width, uint32_t& height) {
+    const SkRect& bounds = path->getBounds();
+
+    const float pathWidth = fmax(bounds.width(), 1.0f);
+    const float pathHeight = fmax(bounds.height(), 1.0f);
+
+    left = bounds.fLeft;
+    top = bounds.fTop;
+
+    offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
+
+    width = uint32_t(pathWidth + offset * 2.0 + 0.5);
+    height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Path cache
 ///////////////////////////////////////////////////////////////////////////////
@@ -69,6 +86,9 @@
     PathCacheEntry entry(path, paint);
     PathTexture* texture = mCache.get(entry);
 
+    float left, top, offset;
+    uint32_t width, height;
+
     if (!texture) {
         texture = addTexture(entry, path, paint);
     } else if (path->getGenerationID() != texture->generation) {
diff --git a/libs/hwui/ShapeCache.h b/libs/hwui/ShapeCache.h
index 30ce690..f180e94 100644
--- a/libs/hwui/ShapeCache.h
+++ b/libs/hwui/ShapeCache.h
@@ -489,18 +489,16 @@
     }
 }
 
+void computePathBounds(const SkPath *path, const SkPaint* paint,
+        float& left, float& top, float& offset, uint32_t& width, uint32_t& height);
+
 template<class Entry>
 PathTexture* ShapeCache<Entry>::addTexture(const Entry& entry, const SkPath *path,
         const SkPaint* paint) {
-    const SkRect& bounds = path->getBounds();
 
-    const float pathWidth = fmax(bounds.width(), 1.0f);
-    const float pathHeight = fmax(bounds.height(), 1.0f);
-
-    const float offset = (int) floorf(fmax(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
-
-    const uint32_t width = uint32_t(pathWidth + offset * 2.0 + 0.5);
-    const uint32_t height = uint32_t(pathHeight + offset * 2.0 + 0.5);
+    float left, top, offset;
+    uint32_t width, height;
+    computePathBounds(path, paint, left, top, offset, width, height);
 
     if (width > mMaxTextureSize || height > mMaxTextureSize) {
         ALOGW("Shape %s too large to be rendered into a texture (%dx%d, max=%dx%d)",
@@ -517,8 +515,8 @@
     }
 
     PathTexture* texture = new PathTexture;
-    texture->left = bounds.fLeft;
-    texture->top = bounds.fTop;
+    texture->left = left;
+    texture->top = top;
     texture->offset = offset;
     texture->width = width;
     texture->height = height;
@@ -542,7 +540,7 @@
     SkSafeUnref(pathPaint.setXfermode(mode));
 
     SkCanvas canvas(bitmap);
-    canvas.translate(-bounds.fLeft + offset, -bounds.fTop + offset);
+    canvas.translate(-left + offset, -top + offset);
     canvas.drawPath(*path, pathPaint);
 
     generateTexture(bitmap, texture);
diff --git a/libs/rs/driver/rsdProgram.cpp b/libs/rs/driver/rsdProgram.cpp
index 852b6bf..fa4cb0f 100644
--- a/libs/rs/driver/rsdProgram.cpp
+++ b/libs/rs/driver/rsdProgram.cpp
@@ -34,8 +34,11 @@
 using namespace android::renderscript;
 
 bool rsdProgramVertexInit(const Context *rsc, const ProgramVertex *pv,
-                          const char* shader, size_t shaderLen) {
-    RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen);
+                          const char* shader, size_t shaderLen,
+                          const char** textureNames, size_t textureNamesCount,
+                          const size_t *textureNamesLength) {
+    RsdShader *drv = new RsdShader(pv, GL_VERTEX_SHADER, shader, shaderLen,
+                                   textureNames, textureNamesCount, textureNamesLength);
     pv->mHal.drv = drv;
 
     return drv->createShader();
@@ -78,8 +81,11 @@
 }
 
 bool rsdProgramFragmentInit(const Context *rsc, const ProgramFragment *pf,
-                          const char* shader, size_t shaderLen) {
-    RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen);
+                            const char* shader, size_t shaderLen,
+                            const char** textureNames, size_t textureNamesCount,
+                            const size_t *textureNamesLength) {
+    RsdShader *drv = new RsdShader(pf, GL_FRAGMENT_SHADER, shader, shaderLen,
+                                   textureNames, textureNamesCount, textureNamesLength);
     pf->mHal.drv = drv;
 
     return drv->createShader();
diff --git a/libs/rs/driver/rsdProgramFragment.h b/libs/rs/driver/rsdProgramFragment.h
index 366cb40..b03a9fe 100644
--- a/libs/rs/driver/rsdProgramFragment.h
+++ b/libs/rs/driver/rsdProgramFragment.h
@@ -22,7 +22,9 @@
 
 bool rsdProgramFragmentInit(const android::renderscript::Context *rsc,
                             const android::renderscript::ProgramFragment *,
-                            const char* shader, uint32_t shaderLen);
+                            const char* shader, size_t shaderLen,
+                            const char** textureNames, size_t textureNamesCount,
+                            const size_t *textureNamesLength);
 void rsdProgramFragmentSetActive(const android::renderscript::Context *rsc,
                                  const android::renderscript::ProgramFragment *);
 void rsdProgramFragmentDestroy(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdProgramVertex.h b/libs/rs/driver/rsdProgramVertex.h
index e998572..f917a41 100644
--- a/libs/rs/driver/rsdProgramVertex.h
+++ b/libs/rs/driver/rsdProgramVertex.h
@@ -21,7 +21,9 @@
 
 bool rsdProgramVertexInit(const android::renderscript::Context *rsc,
                           const android::renderscript::ProgramVertex *,
-                          const char* shader, uint32_t shaderLen);
+                          const char* shader, size_t shaderLen,
+                          const char** textureNames, size_t textureNamesCount,
+                          const size_t *textureNamesLength);
 void rsdProgramVertexSetActive(const android::renderscript::Context *rsc,
                                const android::renderscript::ProgramVertex *);
 void rsdProgramVertexDestroy(const android::renderscript::Context *rsc,
diff --git a/libs/rs/driver/rsdShader.cpp b/libs/rs/driver/rsdShader.cpp
index 0e5b388..1e73b95 100644
--- a/libs/rs/driver/rsdShader.cpp
+++ b/libs/rs/driver/rsdShader.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2011-2012 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.
@@ -30,14 +30,16 @@
 using namespace android::renderscript;
 
 RsdShader::RsdShader(const Program *p, uint32_t type,
-                       const char * shaderText, size_t shaderLength) {
-
+                     const char * shaderText, size_t shaderLength,
+                     const char** textureNames, size_t textureNamesCount,
+                     const size_t *textureNamesLength) {
     mUserShader.setTo(shaderText, shaderLength);
     mRSProgram = p;
     mType = type;
     initMemberVars();
     initAttribAndUniformArray();
-    init();
+    init(textureNames, textureNamesCount, textureNamesLength);
+    createTexturesString(textureNames, textureNamesCount, textureNamesLength);
 }
 
 RsdShader::~RsdShader() {
@@ -65,25 +67,26 @@
     mIsValid = false;
 }
 
-void RsdShader::init() {
+void RsdShader::init(const char** textureNames, size_t textureNamesCount,
+                     const size_t *textureNamesLength) {
     uint32_t attribCount = 0;
     uint32_t uniformCount = 0;
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.inputElementsCount; ct++) {
-        initAddUserElement(mRSProgram->mHal.state.inputElements[ct], mAttribNames, NULL, &attribCount, RS_SHADER_ATTR);
+        initAddUserElement(mRSProgram->mHal.state.inputElements[ct], mAttribNames,
+                           NULL, &attribCount, RS_SHADER_ATTR);
     }
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.constantsCount; ct++) {
-        initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(), mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
+        initAddUserElement(mRSProgram->mHal.state.constantTypes[ct]->getElement(),
+                           mUniformNames, mUniformArraySizes, &uniformCount, RS_SHADER_UNI);
     }
 
     mTextureUniformIndexStart = uniformCount;
-    char buf[256];
     for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
-        snprintf(buf, sizeof(buf), "UNI_Tex%i", ct);
-        mUniformNames[uniformCount].setTo(buf);
+        mUniformNames[uniformCount].setTo("UNI_");
+        mUniformNames[uniformCount].append(textureNames[ct], textureNamesLength[ct]);
         mUniformArraySizes[uniformCount] = 1;
         uniformCount++;
     }
-
 }
 
 String8 RsdShader::getGLSLInputString() const {
@@ -135,22 +138,25 @@
     }
 }
 
-void RsdShader::appendTextures() {
-    char buf[256];
-    for (uint32_t ct=0; ct < mRSProgram->mHal.state.texturesCount; ct++) {
+void RsdShader::createTexturesString(const char** textureNames, size_t textureNamesCount,
+                                     const size_t *textureNamesLength) {
+    mShaderTextures.setTo("");
+    for (uint32_t ct = 0; ct < mRSProgram->mHal.state.texturesCount; ct ++) {
         if (mRSProgram->mHal.state.textureTargets[ct] == RS_TEXTURE_2D) {
             Allocation *a = mRSProgram->mHal.state.textures[ct];
             if (a && a->mHal.state.surfaceTextureID) {
-                snprintf(buf, sizeof(buf), "uniform samplerExternalOES UNI_Tex%i;\n", ct);
+                mShaderTextures.append("uniform samplerExternalOES UNI_");
             } else {
-                snprintf(buf, sizeof(buf), "uniform sampler2D UNI_Tex%i;\n", ct);
+                mShaderTextures.append("uniform sampler2D UNI_");
             }
             mTextureTargets[ct] = GL_TEXTURE_2D;
         } else {
-            snprintf(buf, sizeof(buf), "uniform samplerCube UNI_Tex%i;\n", ct);
+            mShaderTextures.append("uniform samplerCube UNI_");
             mTextureTargets[ct] = GL_TEXTURE_CUBE_MAP;
         }
-        mShader.append(buf);
+
+        mShaderTextures.append(textureNames[ct], textureNamesLength[ct]);
+        mShaderTextures.append(";\n");
     }
 }
 
@@ -161,7 +167,7 @@
     }
     appendUserConstants();
     appendAttributes();
-    appendTextures();
+    mShader.append(mShaderTextures);
 
     mShader.append(mUserShader);
 
@@ -418,7 +424,8 @@
 
         DrvAllocation *drvTex = (DrvAllocation *)mRSProgram->mHal.state.textures[ct]->mHal.drv;
         if (drvTex->glTarget != GL_TEXTURE_2D && drvTex->glTarget != GL_TEXTURE_CUBE_MAP) {
-            ALOGE("Attempting to bind unknown texture to shader id %u, texture unit %u", (uint)this, ct);
+            ALOGE("Attempting to bind unknown texture to shader id %u, texture unit %u",
+                  (uint)this, ct);
             rsc->setError(RS_ERROR_BAD_SHADER, "Non-texture allocation bound to a shader");
         }
         RSD_CALL_GL(glBindTexture, drvTex->glTarget, drvTex->textureID);
diff --git a/libs/rs/driver/rsdShader.h b/libs/rs/driver/rsdShader.h
index 3f0d6ea..e32145f 100644
--- a/libs/rs/driver/rsdShader.h
+++ b/libs/rs/driver/rsdShader.h
@@ -39,7 +39,9 @@
 public:
 
     RsdShader(const android::renderscript::Program *p, uint32_t type,
-               const char * shaderText, uint32_t shaderLength);
+              const char * shaderText, uint32_t shaderLength,
+              const char** textureNames, size_t textureNamesCount,
+              const size_t *textureNamesLength);
     virtual ~RsdShader();
 
     bool createShader();
@@ -67,19 +69,27 @@
 
     // Applies to vertex and fragment shaders only
     void appendUserConstants();
-    void setupUserConstants(const android::renderscript::Context *rsc, RsdShaderCache *sc, bool isFragment);
-    void initAddUserElement(const android::renderscript::Element *e, android::String8 *names, uint32_t *arrayLengths, uint32_t *count, const char *prefix);
+    void setupUserConstants(const android::renderscript::Context *rsc,
+                            RsdShaderCache *sc, bool isFragment);
+    void initAddUserElement(const android::renderscript::Element *e,
+                            android::String8 *names, uint32_t *arrayLengths,
+                            uint32_t *count, const char *prefix);
     void setupTextures(const android::renderscript::Context *rsc, RsdShaderCache *sc);
-    void setupSampler(const android::renderscript::Context *rsc, const android::renderscript::Sampler *s, const android::renderscript::Allocation *tex);
+    void setupSampler(const android::renderscript::Context *rsc,
+                      const android::renderscript::Sampler *s,
+                      const android::renderscript::Allocation *tex);
 
     void appendAttributes();
     void appendTextures();
+    void createTexturesString(const char** textureNames, size_t textureNamesCount,
+                              const size_t *textureNamesLength);
 
     void initAttribAndUniformArray();
 
     mutable bool mDirty;
     android::String8 mShader;
     android::String8 mUserShader;
+    android::String8 mShaderTextures;
     uint32_t mShaderID;
     uint32_t mType;
 
@@ -93,10 +103,14 @@
 
     int32_t mTextureUniformIndexStart;
 
-    void logUniform(const android::renderscript::Element *field, const float *fd, uint32_t arraySize );
-    void setUniform(const android::renderscript::Context *rsc, const android::renderscript::Element *field, const float *fd, int32_t slot, uint32_t arraySize );
+    void logUniform(const android::renderscript::Element *field,
+                    const float *fd, uint32_t arraySize);
+    void setUniform(const android::renderscript::Context *rsc,
+                    const android::renderscript::Element *field,
+                    const float *fd, int32_t slot, uint32_t arraySize );
     void initMemberVars();
-    void init();
+    void init(const char** textureNames, size_t textureNamesCount,
+              const size_t *textureNamesLength);
 };
 
 #endif //ANDROID_RSD_SHADER_H
diff --git a/libs/rs/RenderScript.h b/libs/rs/rs.h
similarity index 98%
rename from libs/rs/RenderScript.h
rename to libs/rs/rs.h
index 6d54268..fbcaf4a 100644
--- a/libs/rs/RenderScript.h
+++ b/libs/rs/rs.h
@@ -24,7 +24,7 @@
 extern "C" {
 #endif
 
-#include "RenderScriptDefines.h"
+#include "rsDefines.h"
 
 //
 // A3D loading and object update code.
diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec
index 491474e..cf4a391 100644
--- a/libs/rs/rs.spec
+++ b/libs/rs/rs.spec
@@ -85,167 +85,167 @@
 
 
 ContextFinish {
-	sync
-	}
+    sync
+    }
 
 ContextBindRootScript {
-	param RsScript sampler
-	}
+    param RsScript sampler
+    }
 
 ContextBindProgramStore {
-	param RsProgramStore pgm
-	}
+    param RsProgramStore pgm
+    }
 
 ContextBindProgramFragment {
-	param RsProgramFragment pgm
-	}
+    param RsProgramFragment pgm
+    }
 
 ContextBindProgramVertex {
-	param RsProgramVertex pgm
-	}
+    param RsProgramVertex pgm
+    }
 
 ContextBindProgramRaster {
-	param RsProgramRaster pgm
-	}
+    param RsProgramRaster pgm
+    }
 
 ContextBindFont {
-	param RsFont pgm
-	}
+    param RsFont pgm
+    }
 
 ContextPause {
-	}
+    }
 
 ContextResume {
-	}
+    }
 
 ContextSetSurface {
-	param uint32_t width
-	param uint32_t height
-	param RsNativeWindow sur
+    param uint32_t width
+    param uint32_t height
+    param RsNativeWindow sur
         sync
-	}
+    }
 
 ContextDump {
-	param int32_t bits
+    param int32_t bits
 }
 
 ContextSetPriority {
-	param int32_t priority
-	}
+    param int32_t priority
+    }
 
 ContextDestroyWorker {
         sync
 }
 
 AssignName {
-	param RsObjectBase obj
-	param const char *name
-	}
+    param RsObjectBase obj
+    param const char *name
+    }
 
 ObjDestroy {
-	param RsAsyncVoidPtr objPtr
-	}
+    param RsAsyncVoidPtr objPtr
+    }
 
 ElementCreate {
         direct
-	param RsDataType mType
-	param RsDataKind mKind
-	param bool mNormalized
-	param uint32_t mVectorSize
-	ret RsElement
-	}
+    param RsDataType mType
+    param RsDataKind mKind
+    param bool mNormalized
+    param uint32_t mVectorSize
+    ret RsElement
+    }
 
 ElementCreate2 {
         direct
-	param const RsElement * elements
-	param const char ** names
-	param const uint32_t * arraySize
-	ret RsElement
-	}
+    param const RsElement * elements
+    param const char ** names
+    param const uint32_t * arraySize
+    ret RsElement
+    }
 
 AllocationCopyToBitmap {
-	param RsAllocation alloc
-	param void * data
-	}
+    param RsAllocation alloc
+    param void * data
+    }
 
 
 Allocation1DData {
-	param RsAllocation va
-	param uint32_t xoff
-	param uint32_t lod
-	param uint32_t count
-	param const void *data
-	}
+    param RsAllocation va
+    param uint32_t xoff
+    param uint32_t lod
+    param uint32_t count
+    param const void *data
+    }
 
 Allocation1DElementData {
-	param RsAllocation va
-	param uint32_t x
-	param uint32_t lod
-	param const void *data
-	param size_t comp_offset
-	}
+    param RsAllocation va
+    param uint32_t x
+    param uint32_t lod
+    param const void *data
+    param size_t comp_offset
+    }
 
 Allocation2DData {
-	param RsAllocation va
-	param uint32_t xoff
-	param uint32_t yoff
-	param uint32_t lod
-	param RsAllocationCubemapFace face
-	param uint32_t w
-	param uint32_t h
-	param const void *data
-	}
+    param RsAllocation va
+    param uint32_t xoff
+    param uint32_t yoff
+    param uint32_t lod
+    param RsAllocationCubemapFace face
+    param uint32_t w
+    param uint32_t h
+    param const void *data
+    }
 
 Allocation2DElementData {
-	param RsAllocation va
-	param uint32_t x
-	param uint32_t y
-	param uint32_t lod
-	param RsAllocationCubemapFace face
-	param const void *data
-	param size_t element_offset
-	}
+    param RsAllocation va
+    param uint32_t x
+    param uint32_t y
+    param uint32_t lod
+    param RsAllocationCubemapFace face
+    param const void *data
+    param size_t element_offset
+    }
 
 AllocationGenerateMipmaps {
-	param RsAllocation va
+    param RsAllocation va
 }
 
 AllocationRead {
-	param RsAllocation va
-	param void * data
-	}
+    param RsAllocation va
+    param void * data
+    }
 
 AllocationSyncAll {
-	param RsAllocation va
-	param RsAllocationUsageType src
+    param RsAllocation va
+    param RsAllocationUsageType src
 }
 
 
 AllocationResize1D {
-	param RsAllocation va
-	param uint32_t dimX
-	}
+    param RsAllocation va
+    param uint32_t dimX
+    }
 
 AllocationResize2D {
-	param RsAllocation va
-	param uint32_t dimX
-	param uint32_t dimY
-	}
+    param RsAllocation va
+    param uint32_t dimX
+    param uint32_t dimY
+    }
 
 AllocationCopy2DRange {
-	param RsAllocation dest
-	param uint32_t destXoff
-	param uint32_t destYoff
-	param uint32_t destMip
-	param uint32_t destFace
-	param uint32_t width
-	param uint32_t height
-	param RsAllocation src
-	param uint32_t srcXoff
-	param uint32_t srcYoff
-	param uint32_t srcMip
-	param uint32_t srcFace
-	}
+    param RsAllocation dest
+    param uint32_t destXoff
+    param uint32_t destYoff
+    param uint32_t destMip
+    param uint32_t destFace
+    param uint32_t width
+    param uint32_t height
+    param RsAllocation src
+    param uint32_t srcXoff
+    param uint32_t srcYoff
+    param uint32_t srcMip
+    param uint32_t srcFace
+    }
 
 SamplerCreate {
     direct
@@ -259,26 +259,26 @@
 }
 
 ScriptBindAllocation {
-	param RsScript vtm
-	param RsAllocation va
-	param uint32_t slot
-	}
+    param RsScript vtm
+    param RsAllocation va
+    param uint32_t slot
+    }
 
 ScriptSetTimeZone {
-	param RsScript s
-	param const char * timeZone
-	}
+    param RsScript s
+    param const char * timeZone
+    }
 
 ScriptInvoke {
-	param RsScript s
-	param uint32_t slot
-	}
+    param RsScript s
+    param uint32_t slot
+    }
 
 ScriptInvokeV {
-	param RsScript s
-	param uint32_t slot
-	param const void * data
-	}
+    param RsScript s
+    param uint32_t slot
+    param const void * data
+    }
 
 ScriptForEach {
     param RsScript s
@@ -289,125 +289,127 @@
 }
 
 ScriptSetVarI {
-	param RsScript s
-	param uint32_t slot
-	param int value
-	}
+    param RsScript s
+    param uint32_t slot
+    param int value
+    }
 
 ScriptSetVarObj {
-	param RsScript s
-	param uint32_t slot
-	param RsObjectBase value
-	}
+    param RsScript s
+    param uint32_t slot
+    param RsObjectBase value
+    }
 
 ScriptSetVarJ {
-	param RsScript s
-	param uint32_t slot
-	param int64_t value
-	}
+    param RsScript s
+    param uint32_t slot
+    param int64_t value
+    }
 
 ScriptSetVarF {
-	param RsScript s
-	param uint32_t slot
-	param float value
-	}
+    param RsScript s
+    param uint32_t slot
+    param float value
+    }
 
 ScriptSetVarD {
-	param RsScript s
-	param uint32_t slot
-	param double value
-	}
+    param RsScript s
+    param uint32_t slot
+    param double value
+    }
 
 ScriptSetVarV {
-	param RsScript s
-	param uint32_t slot
-	param const void * data
-	}
+    param RsScript s
+    param uint32_t slot
+    param const void * data
+    }
 
 
 ScriptCCreate {
         param const char * resName
         param const char * cacheDir
-	param const char * text
-	ret RsScript
-	}
+    param const char * text
+    ret RsScript
+    }
 
 
 ProgramStoreCreate {
-	direct
-	param bool colorMaskR
-	param bool colorMaskG
-	param bool colorMaskB
-	param bool colorMaskA
+    direct
+    param bool colorMaskR
+    param bool colorMaskG
+    param bool colorMaskB
+    param bool colorMaskA
         param bool depthMask
         param bool ditherEnable
-	param RsBlendSrcFunc srcFunc
-	param RsBlendDstFunc destFunc
+    param RsBlendSrcFunc srcFunc
+    param RsBlendDstFunc destFunc
         param RsDepthFunc depthFunc
-	ret RsProgramStore
-	}
+    ret RsProgramStore
+    }
 
 ProgramRasterCreate {
-	direct
-	param bool pointSprite
-	param RsCullMode cull
-	ret RsProgramRaster
+    direct
+    param bool pointSprite
+    param RsCullMode cull
+    ret RsProgramRaster
 }
 
 ProgramBindConstants {
-	param RsProgram vp
-	param uint32_t slot
-	param RsAllocation constants
-	}
+    param RsProgram vp
+    param uint32_t slot
+    param RsAllocation constants
+    }
 
 
 ProgramBindTexture {
-	param RsProgramFragment pf
-	param uint32_t slot
-	param RsAllocation a
-	}
+    param RsProgramFragment pf
+    param uint32_t slot
+    param RsAllocation a
+    }
 
 ProgramBindSampler {
-	param RsProgramFragment pf
-	param uint32_t slot
-	param RsSampler s
-	}
+    param RsProgramFragment pf
+    param uint32_t slot
+    param RsSampler s
+    }
 
 ProgramFragmentCreate {
-	direct
-	param const char * shaderText
-	param const uint32_t * params
-	ret RsProgramFragment
-	}
+    direct
+    param const char * shaderText
+    param const char ** textureNames
+    param const uint32_t * params
+    ret RsProgramFragment
+    }
 
 ProgramVertexCreate {
-	direct
-	param const char * shaderText
-	param const uint32_t * params
-	ret RsProgramVertex
-	}
+    direct
+    param const char * shaderText
+    param const char ** textureNames
+    param const uint32_t * params
+    ret RsProgramVertex
+    }
 
 FontCreateFromFile {
-	param const char *name
-	param float fontSize
-	param uint32_t dpi
-	ret RsFont
-	}
+    param const char *name
+    param float fontSize
+    param uint32_t dpi
+    ret RsFont
+    }
 
 FontCreateFromMemory {
-	param const char *name
-	param float fontSize
-	param uint32_t dpi
-	param const void *data
-	ret RsFont
-	}
+    param const char *name
+    param float fontSize
+    param uint32_t dpi
+    param const void *data
+    ret RsFont
+    }
 
 MeshCreate {
-	param RsAllocation *vtx
-	param RsAllocation *idx
-	param uint32_t *primType
-	ret RsMesh
-	}
+    param RsAllocation *vtx
+    param RsAllocation *idx
+    param uint32_t *primType
+    ret RsMesh
+    }
 
 PathCreate {
     param RsPathPrimitive pp
@@ -417,4 +419,3 @@
     param float quality
     ret RsPath
     }
-
diff --git a/libs/rs/rsContext.cpp b/libs/rs/rsContext.cpp
index adaefc6..95ac76e 100644
--- a/libs/rs/rsContext.cpp
+++ b/libs/rs/rsContext.cpp
@@ -263,6 +263,10 @@
             rsc->timerSet(RS_TIMER_IDLE);
 
 #ifndef ANDROID_RS_SERIALIZE
+            if (!rsc->mRootScript.get() || !rsc->mHasSurface || rsc->mPaused) {
+                targetRate = 0;
+            }
+
             if (vsyncRate != targetRate) {
                 displayEvent.setVsyncRate(targetRate);
                 vsyncRate = targetRate;
diff --git a/libs/rs/RenderScriptDefines.h b/libs/rs/rsDefines.h
similarity index 100%
rename from libs/rs/RenderScriptDefines.h
rename to libs/rs/rsDefines.h
diff --git a/libs/rs/RenderScriptEnv.h b/libs/rs/rsEnv.h
similarity index 100%
rename from libs/rs/RenderScriptEnv.h
rename to libs/rs/rsEnv.h
diff --git a/libs/rs/rsFileA3D.h b/libs/rs/rsFileA3D.h
index 056b5af..baf81de5 100644
--- a/libs/rs/rsFileA3D.h
+++ b/libs/rs/rsFileA3D.h
@@ -17,11 +17,11 @@
 #ifndef ANDROID_RS_FILE_A3D_H
 #define ANDROID_RS_FILE_A3D_H
 
-#include "RenderScript.h"
+#include "rs.h"
 #include "rsMesh.h"
 
+#include <androidfw/Asset.h>
 #include <utils/String8.h>
-#include <utils/Asset.h>
 #include "rsStream.h"
 #include <stdio.h>
 
diff --git a/libs/rs/rsFont.cpp b/libs/rs/rsFont.cpp
index 4f21b3b..c4276cf 100644
--- a/libs/rs/rsFont.cpp
+++ b/libs/rs/rsFont.cpp
@@ -490,8 +490,14 @@
     shaderString.append("  gl_FragColor = col;\n");
     shaderString.append("}\n");
 
-    ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 4);
-    ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32, RS_KIND_USER, false, 1);
+    const char *textureNames[] = { "Tex0" };
+    const size_t textureNamesLengths[] = { 4 };
+    size_t numTextures = sizeof(textureNamesLengths)/sizeof(*textureNamesLengths);
+
+    ObjectBaseRef<const Element> colorElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
+                                                                RS_KIND_USER, false, 4);
+    ObjectBaseRef<const Element> gammaElem = Element::createRef(mRSC, RS_TYPE_FLOAT_32,
+                                                                RS_KIND_USER, false, 1);
     Element::Builder builder;
     builder.add(colorElem.get(), "Color", 1);
     builder.add(gammaElem.get(), "Gamma", 1);
@@ -506,14 +512,17 @@
     tmp[3] = RS_TEXTURE_2D;
 
     mFontShaderFConstant.set(Allocation::createAllocation(mRSC, inputType.get(),
-                                            RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
-    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(),
-                                              shaderString.length(), tmp, 4);
+                                                          RS_ALLOCATION_USAGE_SCRIPT |
+                                                          RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS));
+    ProgramFragment *pf = new ProgramFragment(mRSC, shaderString.string(), shaderString.length(),
+                                              textureNames, numTextures, textureNamesLengths,
+                                              tmp, 4);
     mFontShaderF.set(pf);
     mFontShaderF->bindAllocation(mRSC, mFontShaderFConstant.get(), 0);
 
     mFontSampler.set(Sampler::getSampler(mRSC, RS_SAMPLER_NEAREST, RS_SAMPLER_NEAREST,
-                                         RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP).get());
+                                         RS_SAMPLER_CLAMP, RS_SAMPLER_CLAMP,
+                                         RS_SAMPLER_CLAMP).get());
     mFontShaderF->bindSampler(mRSC, 0, mFontSampler.get());
 
     mFontProgramStore.set(ProgramStore::getProgramStore(mRSC, true, true, true, true,
@@ -525,10 +534,12 @@
 }
 
 void FontState::initTextTexture() {
-    ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8, RS_KIND_PIXEL_A, true, 1);
+    ObjectBaseRef<const Element> alphaElem = Element::createRef(mRSC, RS_TYPE_UNSIGNED_8,
+                                                                RS_KIND_PIXEL_A, true, 1);
 
     // We will allocate a texture to initially hold 32 character bitmaps
-    ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(), 1024, 256, 0, false, false);
+    ObjectBaseRef<Type> texType = Type::getTypeRef(mRSC, alphaElem.get(),
+                                                   1024, 256, 0, false, false);
 
     Allocation *cacheAlloc = Allocation::createAllocation(mRSC, texType.get(),
                                 RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE);
diff --git a/libs/rs/rsFont.h b/libs/rs/rsFont.h
index 4ca794d..88c4795 100644
--- a/libs/rs/rsFont.h
+++ b/libs/rs/rsFont.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_RS_FONT_H
 #define ANDROID_RS_FONT_H
 
-#include "RenderScript.h"
+#include "rs.h"
 #include "rsStream.h"
 #include <utils/String8.h>
 #include <utils/Vector.h>
diff --git a/libs/rs/rsMesh.h b/libs/rs/rsMesh.h
index 166b5d3..8eea427 100644
--- a/libs/rs/rsMesh.h
+++ b/libs/rs/rsMesh.h
@@ -18,7 +18,7 @@
 #define ANDROID_RS_MESH_H
 
 
-#include "RenderScript.h"
+#include "rs.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/rs/rsPath.h b/libs/rs/rsPath.h
index dac795e..7c05503 100644
--- a/libs/rs/rsPath.h
+++ b/libs/rs/rsPath.h
@@ -18,7 +18,7 @@
 #define ANDROID_RS_PATH_H
 
 
-#include "RenderScript.h"
+#include "rs.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/rs/rsProgram.cpp b/libs/rs/rsProgram.cpp
index 8061515..7114f29 100644
--- a/libs/rs/rsProgram.cpp
+++ b/libs/rs/rsProgram.cpp
@@ -20,8 +20,8 @@
 using namespace android;
 using namespace android::renderscript;
 
-Program::Program(Context *rsc, const char * shaderText, uint32_t shaderLength,
-                 const uint32_t * params, uint32_t paramLength)
+Program::Program(Context *rsc, const char * shaderText, size_t shaderLength,
+                 const uint32_t * params, size_t paramLength)
     : ProgramBase(rsc) {
 
     initMemberVars();
diff --git a/libs/rs/rsProgram.h b/libs/rs/rsProgram.h
index 06fc3ec..d032930 100644
--- a/libs/rs/rsProgram.h
+++ b/libs/rs/rsProgram.h
@@ -58,8 +58,8 @@
     };
     Hal mHal;
 
-    Program(Context *, const char * shaderText, uint32_t shaderLength,
-                       const uint32_t * params, uint32_t paramLength);
+    Program(Context *, const char * shaderText, size_t shaderLength,
+            const uint32_t * params, size_t paramLength);
     virtual ~Program();
     virtual bool freeChildren();
 
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index 4e73ca6..bebde1e 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -20,16 +20,18 @@
 using namespace android;
 using namespace android::renderscript;
 
-ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText,
-                                 uint32_t shaderLength, const uint32_t * params,
-                                 uint32_t paramLength)
+ProgramFragment::ProgramFragment(Context *rsc, const char * shaderText, size_t shaderLength,
+                                 const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+
+                                 const uint32_t * params, size_t paramLength)
     : Program(rsc, shaderText, shaderLength, params, paramLength) {
     mConstantColor[0] = 1.f;
     mConstantColor[1] = 1.f;
     mConstantColor[2] = 1.f;
     mConstantColor[3] = 1.f;
 
-    mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length());
+    mRSC->mHal.funcs.fragment.init(mRSC, this, mUserShader.string(), mUserShader.length(),
+                                   textureNames, textureNamesCount, textureNamesLength);
 }
 
 ProgramFragment::~ProgramFragment() {
@@ -110,8 +112,8 @@
 
     Allocation *constAlloc = Allocation::createAllocation(rsc, inputType.get(),
                               RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS);
-    ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(),
-                                              shaderString.length(), tmp, 2);
+    ProgramFragment *pf = new ProgramFragment(rsc, shaderString.string(), shaderString.length(),
+                                              NULL, 0, NULL, tmp, 2);
     pf->bindAllocation(rsc, constAlloc, 0);
     pf->setConstantColor(rsc, 1.0f, 1.0f, 1.0f, 1.0f);
 
@@ -127,9 +129,14 @@
 namespace renderscript {
 
 RsProgramFragment rsi_ProgramFragmentCreate(Context *rsc, const char * shaderText,
-                             size_t shaderLength, const uint32_t * params,
-                             size_t paramLength) {
-    ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength, params, paramLength);
+                                            size_t shaderLength,
+                                            const char** textureNames,
+                                            size_t textureNamesCount,
+                                            const size_t *textureNamesLength,
+                                            const uint32_t * params, size_t paramLength) {
+    ProgramFragment *pf = new ProgramFragment(rsc, shaderText, shaderLength,
+                                              textureNames, textureNamesCount, textureNamesLength,
+                                              params, paramLength);
     pf->incUserRef();
     //ALOGE("rsi_ProgramFragmentCreate %p", pf);
     return pf;
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index d6e20cd..4eb28e7 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -27,9 +27,9 @@
 
 class ProgramFragment : public Program {
 public:
-    ProgramFragment(Context *rsc, const char * shaderText,
-                             uint32_t shaderLength, const uint32_t * params,
-                             uint32_t paramLength);
+    ProgramFragment(Context *rsc, const char * shaderText, size_t shaderLength,
+                    const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+                     const uint32_t * params, size_t paramLength);
     virtual ~ProgramFragment();
 
     virtual void setup(Context *, ProgramFragmentState *);
diff --git a/libs/rs/rsProgramVertex.cpp b/libs/rs/rsProgramVertex.cpp
index 871caac..c8a53ea 100644
--- a/libs/rs/rsProgramVertex.cpp
+++ b/libs/rs/rsProgramVertex.cpp
@@ -21,11 +21,13 @@
 using namespace android::renderscript;
 
 
-ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText,
-                             uint32_t shaderLength, const uint32_t * params,
-                             uint32_t paramLength)
+ProgramVertex::ProgramVertex(Context *rsc, const char * shaderText, size_t shaderLength,
+                             const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+
+                             const uint32_t * params, size_t paramLength)
     : Program(rsc, shaderText, shaderLength, params, paramLength) {
-    mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length());
+    mRSC->mHal.funcs.vertex.init(mRSC, this, mUserShader.string(), mUserShader.length(),
+                                 textureNames, textureNamesCount, textureNamesLength);
 }
 
 ProgramVertex::~ProgramVertex() {
@@ -191,8 +193,8 @@
     tmp[2] = RS_PROGRAM_PARAM_INPUT;
     tmp[3] = (uint32_t)attrElem.get();
 
-    ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(),
-                                          shaderString.length(), tmp, 4);
+    ProgramVertex *pv = new ProgramVertex(rsc, shaderString.string(), shaderString.length(),
+                                          NULL, 0, NULL, tmp, 4);
     Allocation *alloc = Allocation::createAllocation(rsc, inputType.get(),
                               RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS);
     pv->bindAllocation(rsc, alloc, 0);
@@ -229,10 +231,13 @@
 namespace android {
 namespace renderscript {
 
-RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText,
-                             size_t shaderLength, const uint32_t * params,
-                             size_t paramLength) {
-    ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength, params, paramLength);
+RsProgramVertex rsi_ProgramVertexCreate(Context *rsc, const char * shaderText, size_t shaderLength,
+                                        const char** textureNames, size_t textureNamesCount,
+                                        const size_t *textureNamesLength,
+                                        const uint32_t * params, size_t paramLength) {
+    ProgramVertex *pv = new ProgramVertex(rsc, shaderText, shaderLength,
+                                          textureNames, textureNamesCount, textureNamesLength,
+                                          params, paramLength);
     pv->incUserRef();
     return pv;
 }
diff --git a/libs/rs/rsProgramVertex.h b/libs/rs/rsProgramVertex.h
index 5cfdd8b..67c2a88 100644
--- a/libs/rs/rsProgramVertex.h
+++ b/libs/rs/rsProgramVertex.h
@@ -27,8 +27,9 @@
 
 class ProgramVertex : public Program {
 public:
-    ProgramVertex(Context *,const char * shaderText, uint32_t shaderLength,
-                  const uint32_t * params, uint32_t paramLength);
+    ProgramVertex(Context *,const char * shaderText, size_t shaderLength,
+                  const char** textureNames, size_t textureNamesCount, const size_t *textureNamesLength,
+                  const uint32_t * params, size_t paramLength);
     virtual ~ProgramVertex();
 
     virtual void setup(Context *rsc, ProgramVertexState *state);
diff --git a/libs/rs/rsSampler.h b/libs/rs/rsSampler.h
index 654cd9c..013e4ca 100644
--- a/libs/rs/rsSampler.h
+++ b/libs/rs/rsSampler.h
@@ -18,7 +18,7 @@
 #define ANDROID_RS_SAMPLER_H
 
 #include "rsAllocation.h"
-#include "RenderScript.h"
+#include "rs.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h
index c65a5bf..fc4df51 100644
--- a/libs/rs/rsScriptC.h
+++ b/libs/rs/rsScriptC.h
@@ -19,7 +19,7 @@
 
 #include "rsScript.h"
 
-#include "RenderScriptEnv.h"
+#include "rsEnv.h"
 
 #ifndef ANDROID_RS_SERIALIZE
 #include "bcinfo/BitcodeTranslator.h"
diff --git a/libs/rs/rsThreadIO.cpp b/libs/rs/rsThreadIO.cpp
index 4f30573..7182f53 100644
--- a/libs/rs/rsThreadIO.cpp
+++ b/libs/rs/rsThreadIO.cpp
@@ -31,6 +31,8 @@
 
 ThreadIO::ThreadIO() {
     mRunning = true;
+    mPureFifo = false;
+    mMaxInlineSize = 1024;
 }
 
 ThreadIO::~ThreadIO() {
@@ -65,6 +67,16 @@
     mToClient.shutdown();
 }
 
+void ThreadIO::coreWrite(const void *data, size_t len) {
+    //ALOGV("core write %p %i", data, (int)len);
+    mToCore.writeAsync(data, len, true);
+}
+
+void ThreadIO::coreRead(void *data, size_t len) {
+    //ALOGV("core read %p %i", data, (int)len);
+    mToCore.read(data, len);
+}
+
 void ThreadIO::coreSetReturn(const void *data, size_t dataLen) {
     uint32_t buf;
     if (data == NULL) {
@@ -91,6 +103,7 @@
 
 bool ThreadIO::playCoreCommands(Context *con, int waitFd) {
     bool ret = false;
+    const bool isLocal = !isPureFifo();
 
     uint8_t buf[2 * 1024];
     const CoreCmdHeader *cmd = (const CoreCmdHeader *)&buf[0];
@@ -120,14 +133,19 @@
         }
 
         if (p[0].revents) {
-            size_t r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
-            mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
-
-            if (r != sizeof(CoreCmdHeader)) {
-                // exception or timeout occurred.
-                break;
+            size_t r = 0;
+            if (isLocal) {
+                r = mToCore.read(&buf[0], sizeof(CoreCmdHeader));
+                mToCore.read(&buf[sizeof(CoreCmdHeader)], cmd->bytes);
+                if (r != sizeof(CoreCmdHeader)) {
+                    // exception or timeout occurred.
+                    break;
+                }
+            } else {
+                r = mToCore.read((void *)&cmd->cmdID, sizeof(cmd->cmdID));
             }
 
+
             ret = true;
             if (con->props.mLogTimes) {
                 con->timerSet(Context::RS_TIMER_INTERNAL);
@@ -138,7 +156,12 @@
                 rsAssert(cmd->cmdID < (sizeof(gPlaybackFuncs) / sizeof(void *)));
                 ALOGE("playCoreCommands error con %p, cmd %i", con, cmd->cmdID);
             }
-            gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
+
+            if (isLocal) {
+                gPlaybackFuncs[cmd->cmdID](con, data, cmd->bytes);
+            } else {
+                gPlaybackRemoteFuncs[cmd->cmdID](con, this);
+            }
 
             if (con->props.mLogTimes) {
                 con->timerSet(Context::RS_TIMER_IDLE);
diff --git a/libs/rs/rsThreadIO.h b/libs/rs/rsThreadIO.h
index 62e3e33..cb7d4ab 100644
--- a/libs/rs/rsThreadIO.h
+++ b/libs/rs/rsThreadIO.h
@@ -34,6 +34,13 @@
     void init();
     void shutdown();
 
+    size_t getMaxInlineSize() {
+        return mMaxInlineSize;
+    }
+    bool isPureFifo() {
+        return mPureFifo;
+    }
+
     // Plays back commands from the client.
     // Returns true if any commands were processed.
     bool playCoreCommands(Context *con, int waitFd);
@@ -42,8 +49,16 @@
 
     void * coreHeader(uint32_t, size_t dataLen);
     void coreCommit();
+
     void coreSetReturn(const void *data, size_t dataLen);
     void coreGetReturn(void *data, size_t dataLen);
+    void coreWrite(const void *data, size_t len);
+    void coreRead(void *data, size_t len);
+
+    void asyncSetReturn(const void *data, size_t dataLen);
+    void asyncGetReturn(void *data, size_t dataLen);
+    void asyncWrite(const void *data, size_t len);
+    void asyncRead(void *data, size_t len);
 
 
     RsMessageToClientType getClientHeader(size_t *receiveLen, uint32_t *usrID);
@@ -65,6 +80,8 @@
     ClientCmdHeader mLastClientHeader;
 
     bool mRunning;
+    bool mPureFifo;
+    size_t mMaxInlineSize;
 
     FifoSocket mToClient;
     FifoSocket mToCore;
diff --git a/libs/rs/rsUtils.h b/libs/rs/rsUtils.h
index db6f592..a9a992a 100644
--- a/libs/rs/rsUtils.h
+++ b/libs/rs/rsUtils.h
@@ -34,7 +34,7 @@
 
 #include <math.h>
 
-#include "RenderScript.h"
+#include "rs.h"
 
 namespace android {
 namespace renderscript {
diff --git a/libs/rs/rs_hal.h b/libs/rs/rs_hal.h
index 12ace43..e4bf17f 100644
--- a/libs/rs/rs_hal.h
+++ b/libs/rs/rs_hal.h
@@ -17,7 +17,7 @@
 #ifndef RS_HAL_H
 #define RS_HAL_H
 
-#include <RenderScriptDefines.h>
+#include <rsDefines.h>
 
 struct ANativeWindow;
 
@@ -178,14 +178,18 @@
 
     struct {
         bool (*init)(const Context *rsc, const ProgramVertex *pv,
-                     const char* shader, size_t shaderLen);
+                     const char* shader, size_t shaderLen,
+                     const char** textureNames, size_t textureNamesCount,
+                     const size_t *textureNamesLength);
         void (*setActive)(const Context *rsc, const ProgramVertex *pv);
         void (*destroy)(const Context *rsc, const ProgramVertex *pv);
     } vertex;
 
     struct {
         bool (*init)(const Context *rsc, const ProgramFragment *pf,
-                     const char* shader, size_t shaderLen);
+                     const char* shader, size_t shaderLen,
+                     const char** textureNames, size_t textureNamesCount,
+                     const size_t *textureNamesLength);
         void (*setActive)(const Context *rsc, const ProgramFragment *pf);
         void (*destroy)(const Context *rsc, const ProgramFragment *pf);
     } fragment;
diff --git a/libs/rs/rsg_generator.c b/libs/rs/rsg_generator.c
index 385c8b5..99c305e 100644
--- a/libs/rs/rsg_generator.c
+++ b/libs/rs/rsg_generator.c
@@ -238,7 +238,7 @@
             //fprintf(f, "    ALOGE(\"add command %s\\n\");\n", api->name);
             if (hasInlineDataPointers(api)) {
                 fprintf(f, "    RS_CMD_%s *cmd = NULL;\n", api->name);
-                fprintf(f, "    if (dataSize < 1024) {;\n");
+                fprintf(f, "    if (dataSize < io->getMaxInlineSize()) {;\n");
                 fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, dataSize + size));\n", api->name, api->name);
                 fprintf(f, "    } else {\n");
                 fprintf(f, "        cmd = static_cast<RS_CMD_%s *>(io->coreHeader(RS_CMD_ID_%s, size));\n", api->name, api->name);
@@ -252,7 +252,7 @@
                 const VarType *vt = &api->params[ct2];
                 needFlush += vt->ptrLevel;
                 if (vt->ptrLevel && hasInlineDataPointers(api)) {
-                    fprintf(f, "    if (dataSize < 1024) {\n");
+                    fprintf(f, "    if (dataSize < io->getMaxInlineSize()) {\n");
                     fprintf(f, "        memcpy(payload, %s, %s_length);\n", vt->name, vt->name);
                     fprintf(f, "        cmd->%s = (", vt->name);
                     printVarType(f, vt);
@@ -272,7 +272,7 @@
 
             fprintf(f, "    io->coreCommit();\n");
             if (hasInlineDataPointers(api)) {
-                fprintf(f, "    if (dataSize >= 1024) {\n");
+                fprintf(f, "    if (dataSize >= io->getMaxInlineSize()) {\n");
                 fprintf(f, "        io->coreGetReturn(NULL, 0);\n");
                 fprintf(f, "    }\n");
             } else if (api->ret.typeName[0]) {
@@ -288,81 +288,71 @@
         fprintf(f, "};\n\n");
 
 
+        // Generate a remote sender function
+        const char * str = "core";
+        if (api->direct) {
+            str = "async";
+        }
+
         fprintf(f, "static ");
         printFuncDecl(f, api, "RF_", 0, 0);
         fprintf(f, "\n{\n");
-        fprintf(f, "    Fifo *f = NULL;\n");
-        fprintf(f, "    RS_CMD_%s cmd;\n", api->name);
-        fprintf(f, "    const uint32_t cmdSize = sizeof(cmd);\n");
+        fprintf(f, "    ThreadIO *io = &((Context *)rsc)->mIO;\n");
         fprintf(f, "    const uint32_t cmdID = RS_CMD_ID_%s;\n", api->name);
-        fprintf(f, "    f->writeAsync(&cmdID, sizeof(cmdID));\n");
-        fprintf(f, "    intptr_t offset = cmdSize;\n");
-        fprintf(f, "    uint32_t dataSize = 0;\n");
+        fprintf(f, "    io->%sWrite(&cmdID, sizeof(cmdID));\n\n", str);
+
         for (ct2=0; ct2 < api->paramCount; ct2++) {
             const VarType *vt = &api->params[ct2];
-            if (vt->isConst && vt->ptrLevel) {
-                switch(vt->ptrLevel) {
-                case 1:
-                    fprintf(f, "    dataSize += %s_length;\n", vt->name);
-                    break;
-                case 2:
-                    fprintf(f, "    for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
-                    fprintf(f, "        dataSize += %s_length[ct];\n", vt->name);
-                    fprintf(f, "    }\n");
-                    break;
-                default:
-                    printf("pointer level not handled!!");
-                }
+            if (vt->ptrLevel == 0) {
+                fprintf(f, "    io->%sWrite(& %s, sizeof(%s));\n", str, vt->name, vt->name);
             }
         }
         fprintf(f, "\n");
 
         for (ct2=0; ct2 < api->paramCount; ct2++) {
             const VarType *vt = &api->params[ct2];
-            switch(vt->ptrLevel) {
-            case 0:
-                fprintf(f, "    cmd.%s = %s;\n", vt->name, vt->name);
-                break;
-            case 1:
-                fprintf(f, "    cmd.%s = (", vt->name);
-                printVarType(f, vt);
-                fprintf(f, ")offset;\n");
-                fprintf(f, "    offset += %s_length;\n", vt->name);
-                break;
-            case 2:
-                fprintf(f, "    cmd.%s = (", vt->name);
-                printVarType(f, vt);
-                fprintf(f, ")offset;\n");
-                fprintf(f, "    for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
-                fprintf(f, "        offset += %s_length[ct];\n", vt->name);
-                fprintf(f, "    }\n");
-                break;
-            default:
-                fprintf(stderr, "pointer level not handled!!");
+            if ((vt->ptrLevel == 1) && (vt->isConst)) {
+                fprintf(f, "    io->%sWrite(%s, %s_length);\n", str, vt->name, vt->name);
             }
         }
         fprintf(f, "\n");
 
-        fprintf(f, "    f->writeAsync(&cmd, cmdSize);\n");
         for (ct2=0; ct2 < api->paramCount; ct2++) {
             const VarType *vt = &api->params[ct2];
-            if (vt->ptrLevel == 1) {
-                fprintf(f, "    f->writeAsync(%s, %s_length);\n", vt->name, vt->name);
-            }
-            if (vt->ptrLevel == 2) {
+            if ((vt->ptrLevel == 2) && (vt->isConst)) {
                 fprintf(f, "    for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
-                fprintf(f, "        f->writeAsync(%s, %s_length[ct]);\n", vt->name, vt->name);
-                fprintf(f, "        offset += %s_length[ct];\n", vt->name);
+                fprintf(f, "        io->%sWrite(%s[ct], %s_length[ct]);\n", str, vt->name, vt->name);
                 fprintf(f, "    }\n");
             }
         }
+        fprintf(f, "\n");
+
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
+            if ((vt->ptrLevel == 1) && (!vt->isConst)) {
+                fprintf(f, "    io->%sGetReturn(%s, %s_length);\n", str, vt->name, vt->name);
+            }
+        }
+        fprintf(f, "\n");
+
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
+            if ((vt->ptrLevel == 2) && (!vt->isConst)) {
+                fprintf(f, "    for (size_t ct = 0; ct < (%s_length_length / sizeof(%s_length)); ct++) {\n", vt->name, vt->name);
+                fprintf(f, "        io->%sGetReturn(%s[ct], %s_length[ct]);\n", str, vt->name, vt->name);
+                fprintf(f, "    }\n");
+            }
+        }
+        fprintf(f, "\n");
 
         if (api->ret.typeName[0]) {
             fprintf(f, "    ");
             printVarType(f, &api->ret);
             fprintf(f, " retValue;\n");
-            fprintf(f, "    f->writeWaitReturn(&retValue, sizeof(retValue));\n");
+            fprintf(f, "    io->%sGetReturn(&retValue, sizeof(retValue));\n", str);
             fprintf(f, "    return retValue;\n");
+        } else /*if (api->sync)*/ {
+            fprintf(f, "    io->%sGetReturn(NULL, 0);\n", str);
         }
         fprintf(f, "}\n\n");
     }
@@ -418,7 +408,6 @@
     fprintf(f, "#include \"rsDevice.h\"\n");
     fprintf(f, "#include \"rsContext.h\"\n");
     fprintf(f, "#include \"rsThreadIO.h\"\n");
-    //fprintf(f, "#include \"rsgApiStructs.h\"\n");
     fprintf(f, "#include \"rsgApiFuncDecl.h\"\n");
     fprintf(f, "\n");
     fprintf(f, "namespace android {\n");
@@ -434,8 +423,6 @@
         }
 
         fprintf(f, "void rsp_%s(Context *con, const void *vp, size_t cmdSizeBytes) {\n", api->name);
-
-        //fprintf(f, "    ALOGE(\"play command %s\\n\");\n", api->name);
         fprintf(f, "    const RS_CMD_%s *cmd = static_cast<const RS_CMD_%s *>(vp);\n", api->name, api->name);
 
         if (hasInlineDataPointers(api)) {
@@ -488,30 +475,40 @@
         const ApiEntry * api = &apis[ct];
         int needFlush = 0;
 
-        fprintf(f, "void rspr_%s(Context *con, Fifo *f, uint8_t *scratch, size_t scratchSize) {\n", api->name);
-
-        //fprintf(f, "    ALOGE(\"play command %s\\n\");\n", api->name);
+        fprintf(f, "void rspr_%s(Context *con, ThreadIO *io) {\n", api->name);
         fprintf(f, "    RS_CMD_%s cmd;\n", api->name);
-        fprintf(f, "    f->read(&cmd, sizeof(cmd));\n");
 
         for (ct2=0; ct2 < api->paramCount; ct2++) {
             const VarType *vt = &api->params[ct2];
-            needFlush += vt->ptrLevel;
+            if (vt->ptrLevel == 0) {
+                fprintf(f, "    io->coreRead(&cmd.%s, sizeof(cmd.%s));\n", vt->name, vt->name);
+            }
+        }
+        fprintf(f, "\n");
+
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
             if (vt->ptrLevel == 1) {
                 fprintf(f, "    cmd.%s = (", vt->name);
                 printVarType(f, vt);
-                fprintf(f, ")scratch;\n");
-                fprintf(f, "    f->read(scratch, cmd.%s_length);\n", vt->name);
-                fprintf(f, "    scratch += cmd.%s_length;\n", vt->name);
+                fprintf(f, ")malloc(cmd.%s_length);\n", vt->name);
+
+                if (vt->isConst) {
+                    fprintf(f, "    if (cmd.%s_length) io->coreRead((void *)cmd.%s, cmd.%s_length);\n", vt->name, vt->name, vt->name);
+                }
             }
+        }
+        fprintf(f, "\n");
+
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
             if (vt->ptrLevel == 2) {
-                fprintf(f, "    size_t sum_%s = 0;\n", vt->name);
                 fprintf(f, "    for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name);
-                fprintf(f, "        ((size_t *)scratch)[ct] = cmd.%s_length[ct];\n", vt->name);
-                fprintf(f, "        sum_%s += cmd.%s_length[ct];\n", vt->name, vt->name);
+                fprintf(f, "        cmd.%s = (", vt->name);
+                printVarType(f, vt);
+                fprintf(f, ")malloc(cmd.%s_length[ct]);\n", vt->name);
+                fprintf(f, "        io->coreRead(& cmd.%s, cmd.%s_length[ct]);\n", vt->name, vt->name);
                 fprintf(f, "    }\n");
-                fprintf(f, "    f->read(scratch, sum_%s);\n", vt->name);
-                fprintf(f, "    scratch += sum_%s;\n", vt->name);
             }
         }
         fprintf(f, "\n");
@@ -535,10 +532,42 @@
         }
         fprintf(f, ");\n");
 
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
+            if ((vt->ptrLevel == 1) && (!vt->isConst)) {
+                fprintf(f, "    io->coreSetReturn((void *)cmd.%s, cmd.%s_length);\n", vt->name, vt->name);
+            }
+        }
+
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
+            if ((vt->ptrLevel == 2) && (!vt->isConst)) {
+                fprintf(f, "    for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name);
+                fprintf(f, "        io->coreSetReturn((void *)cmd.%s[ct], cmd.%s_length[ct]);\n", vt->name, vt->name);
+                fprintf(f, "    }\n");
+            }
+        }
+        fprintf(f, "\n");
+
         if (api->ret.typeName[0]) {
-            fprintf(f, "    f->readReturn(&ret, sizeof(ret));\n");
-        } else if (needFlush) {
-            fprintf(f, "    f->readReturn(NULL, 0);\n");
+            fprintf(f, "    io->coreSetReturn(&ret, sizeof(ret));\n");
+        } else /*if (needFlush)*/ {
+            fprintf(f, "    io->coreSetReturn(NULL, 0);\n");
+        }
+
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
+            if (vt->ptrLevel == 1) {
+                fprintf(f, "    free((void *)cmd.%s);\n", vt->name);
+            }
+        }
+        for (ct2=0; ct2 < api->paramCount; ct2++) {
+            const VarType *vt = &api->params[ct2];
+            if (vt->ptrLevel == 2) {
+                fprintf(f, "    for (size_t ct = 0; ct < (cmd.%s_length_length / sizeof(cmd.%s_length)); ct++) {\n", vt->name, vt->name);
+                fprintf(f, "        free((void *)cmd.%s);\n", vt->name);
+                fprintf(f, "    }\n");
+            }
         }
 
         fprintf(f, "};\n\n");
@@ -608,7 +637,7 @@
             fprintf(f, "    uint32_t size;\n");
             fprintf(f, "} RsPlaybackRemoteHeader;\n\n");
             fprintf(f, "typedef void (*RsPlaybackLocalFunc)(Context *, const void *, size_t sizeBytes);\n");
-            fprintf(f, "typedef void (*RsPlaybackRemoteFunc)(Context *, Fifo *, uint8_t *scratch, size_t scratchSize);\n");
+            fprintf(f, "typedef void (*RsPlaybackRemoteFunc)(Context *, ThreadIO *);\n");
             fprintf(f, "extern RsPlaybackLocalFunc gPlaybackFuncs[%i];\n", apiCount + 1);
             fprintf(f, "extern RsPlaybackRemoteFunc gPlaybackRemoteFuncs[%i];\n", apiCount + 1);
 
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index f8b4452..f0d7b02 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -13,41 +13,14 @@
 # limitations under the License.
 
 LOCAL_PATH:= $(call my-dir)
-
-# libui is partially built for the host (used by build time keymap validation tool)
-# These files are common to host and target builds.
-commonSources:= \
-	Input.cpp \
-	Keyboard.cpp \
-	KeyLayoutMap.cpp \
-	KeyCharacterMap.cpp \
-	VirtualKeyMap.cpp
-
-# For the host
-# =====================================================
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= $(commonSources)
-
-LOCAL_MODULE:= libui
-
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# For the device
-# =====================================================
-
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES:= \
-	$(commonSources) \
 	EGLUtils.cpp \
 	FramebufferNativeWindow.cpp \
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
 	GraphicBufferMapper.cpp \
-	InputTransport.cpp \
 	PixelFormat.cpp \
 	Rect.cpp \
 	Region.cpp
@@ -56,14 +29,7 @@
 	libcutils \
 	libutils \
 	libEGL \
-	libpixelflinger \
-	libhardware \
-	libhardware_legacy \
-	libskia \
-	libbinder
-
-LOCAL_C_INCLUDES := \
-    external/skia/include/core
+	libhardware
 
 LOCAL_MODULE:= libui
 
diff --git a/libs/ui/PixelFormat.cpp b/libs/ui/PixelFormat.cpp
index ee186c8..6993dac 100644
--- a/libs/ui/PixelFormat.cpp
+++ b/libs/ui/PixelFormat.cpp
@@ -15,13 +15,51 @@
  */
 
 #include <ui/PixelFormat.h>
-#include <pixelflinger/format.h>
 #include <hardware/hardware.h>
 
+// ----------------------------------------------------------------------------
 namespace android {
+// ----------------------------------------------------------------------------
 
 static const int COMPONENT_YUV = 0xFF;
 
+struct Info {
+    size_t      size;
+    size_t      bitsPerPixel;
+    struct {
+        uint8_t     ah;
+        uint8_t     al;
+        uint8_t     rh;
+        uint8_t     rl;
+        uint8_t     gh;
+        uint8_t     gl;
+        uint8_t     bh;
+        uint8_t     bl;
+    };
+    uint8_t     components;
+};
+
+static Info const sPixelFormatInfos[] = {
+        { 0,  0, { 0, 0,   0, 0,   0, 0,   0, 0 }, 0 },
+        { 4, 32, {32,24,   8, 0,  16, 8,  24,16 }, PixelFormatInfo::RGBA },
+        { 4, 24, { 0, 0,   8, 0,  16, 8,  24,16 }, PixelFormatInfo::RGB  },
+        { 3, 24, { 0, 0,   8, 0,  16, 8,  24,16 }, PixelFormatInfo::RGB  },
+        { 2, 16, { 0, 0,  16,11,  11, 5,   5, 0 }, PixelFormatInfo::RGB  },
+        { 4, 32, {32,24,  24,16,  16, 8,   8, 0 }, PixelFormatInfo::RGBA },
+        { 2, 16, { 1, 0,  16,11,  11, 6,   6, 1 }, PixelFormatInfo::RGBA },
+        { 2, 16, { 4, 0,  16,12,  12, 8,   8, 4 }, PixelFormatInfo::RGBA },
+        { 1,  8, { 8, 0,   0, 0,   0, 0,   0, 0 }, PixelFormatInfo::ALPHA}
+};
+
+static const Info* gGetPixelFormatTable(size_t* numEntries) {
+    if (numEntries) {
+        *numEntries = sizeof(sPixelFormatInfos)/sizeof(Info);
+    }
+    return sPixelFormatInfos;
+}
+
+// ----------------------------------------------------------------------------
+
 size_t PixelFormatInfo::getScanlineSize(unsigned int width) const
 {
     size_t size;
@@ -77,27 +115,12 @@
     }
 
     size_t numEntries;
-    const GGLFormat *i = gglGetPixelFormatTable(&numEntries) + format;
+    const Info *i = gGetPixelFormatTable(&numEntries) + format;
     bool valid = uint32_t(format) < numEntries;
     if (!valid) {
         return BAD_INDEX;
     }
 
-    #define COMPONENT(name) \
-        case GGL_##name: info->components = PixelFormatInfo::name; break;
-    
-    switch (i->components) {
-        COMPONENT(ALPHA)
-        COMPONENT(RGB)
-        COMPONENT(RGBA)
-        COMPONENT(LUMINANCE)
-        COMPONENT(LUMINANCE_ALPHA)
-        default:
-            return BAD_INDEX;
-    }
-    
-    #undef COMPONENT
-    
     info->format = format;
     info->bytesPerPixel = i->size;
     info->bitsPerPixel  = i->bitsPerPixel;
@@ -109,9 +132,12 @@
     info->l_green       = i->gl;
     info->h_blue        = i->bh;
     info->l_blue        = i->bl;
+    info->components    = i->components;
 
     return NO_ERROR;
 }
 
+// ----------------------------------------------------------------------------
 }; // namespace android
+// ----------------------------------------------------------------------------
 
diff --git a/libs/ui/tests/Android.mk b/libs/ui/tests/Android.mk
index 700b604..50cad36 100644
--- a/libs/ui/tests/Android.mk
+++ b/libs/ui/tests/Android.mk
@@ -2,47 +2,5 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
-# Build the unit tests.
-test_src_files := \
-    InputChannel_test.cpp \
-    InputEvent_test.cpp \
-    InputPublisherAndConsumer_test.cpp
-
-shared_libraries := \
-	libcutils \
-	libutils \
-	libEGL \
-	libbinder \
-	libpixelflinger \
-	libhardware \
-	libhardware_legacy \
-	libui \
-	libstlport \
-	libskia
-
-static_libraries := \
-	libgtest \
-	libgtest_main
-
-c_includes := \
-    bionic \
-    bionic/libstdc++/include \
-    external/gtest/include \
-    external/stlport/stlport \
-    external/skia/include/core
-
-module_tags := eng tests
-
-$(foreach file,$(test_src_files), \
-    $(eval include $(CLEAR_VARS)) \
-    $(eval LOCAL_SHARED_LIBRARIES := $(shared_libraries)) \
-    $(eval LOCAL_STATIC_LIBRARIES := $(static_libraries)) \
-    $(eval LOCAL_C_INCLUDES := $(c_includes)) \
-    $(eval LOCAL_SRC_FILES := $(file)) \
-    $(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
-    $(eval LOCAL_MODULE_TAGS := $(module_tags)) \
-    $(eval include $(BUILD_EXECUTABLE)) \
-)
-
 # Build the manual test programs.
 include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 24cf504..a96c8e6 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -18,9 +18,6 @@
 # and once for the device.
 
 commonSources:= \
-	Asset.cpp \
-	AssetDir.cpp \
-	AssetManager.cpp \
 	BasicHashtable.cpp \
 	BlobCache.cpp \
 	BufferedTextOutput.cpp \
@@ -29,14 +26,11 @@
 	FileMap.cpp \
 	Flattenable.cpp \
 	LinearTransform.cpp \
-	ObbFile.cpp \
 	PropertyMap.cpp \
 	RefBase.cpp \
-	ResourceTypes.cpp \
 	SharedBuffer.cpp \
 	Static.cpp \
 	StopWatch.cpp \
-	StreamingZipInflater.cpp \
 	String8.cpp \
 	String16.cpp \
 	StringArray.cpp \
@@ -47,9 +41,6 @@
 	Tokenizer.cpp \
 	Unicode.cpp \
 	VectorImpl.cpp \
-	ZipFileCRO.cpp \
-	ZipFileRO.cpp \
-	ZipUtils.cpp \
 	misc.cpp
 
 
@@ -63,7 +54,6 @@
 LOCAL_MODULE:= libutils
 
 LOCAL_CFLAGS += -DLIBUTILS_NATIVE=1 $(TOOL_CFLAGS)
-LOCAL_C_INCLUDES += external/zlib
 
 ifeq ($(HOST_OS),windows)
 ifeq ($(strip $(USE_CYGWIN),),)
@@ -79,7 +69,6 @@
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
-
 # For the device
 # =====================================================
 include $(CLEAR_VARS)
@@ -88,8 +77,6 @@
 # we have the common sources, plus some device-specific stuff
 LOCAL_SRC_FILES:= \
 	$(commonSources) \
-	BackupData.cpp \
-	BackupHelpers.cpp \
 	Looper.cpp
 
 ifeq ($(TARGET_OS),linux)
@@ -97,14 +84,11 @@
 endif
 
 LOCAL_C_INCLUDES += \
-		external/zlib \
-		external/icu4c/common \
 		bionic/libc/private
 
 LOCAL_LDLIBS += -lpthread
 
 LOCAL_SHARED_LIBRARIES := \
-	libz \
 	liblog \
 	libcutils \
 	libdl \
@@ -113,19 +97,6 @@
 LOCAL_MODULE:= libutils
 include $(BUILD_SHARED_LIBRARY)
 
-ifeq ($(TARGET_OS),linux)
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES += \
-		external/zlib \
-		external/icu4c/common \
-		bionic/libc/private
-LOCAL_LDLIBS := -lrt -ldl -lpthread
-LOCAL_MODULE := libutils
-LOCAL_SRC_FILES := $(commonSources) BackupData.cpp BackupHelpers.cpp
-include $(BUILD_STATIC_LIBRARY)
-endif
-
-
 # Include subdirectory makefiles
 # ============================================================
 
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 58230f4..a6811fc 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -7,10 +7,8 @@
 	BasicHashtable_test.cpp \
 	BlobCache_test.cpp \
 	Looper_test.cpp \
-	ObbFile_test.cpp \
 	String8_test.cpp \
 	Unicode_test.cpp \
-	ZipFileRO_test.cpp \
 
 shared_libraries := \
 	libz \
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index eae03be..1c7f577 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -591,7 +591,7 @@
                         // Post a persist volume msg
                         sendMsg(mAudioHandler,
                                 MSG_PERSIST_VOLUME,
-                                SENDMSG_REPLACE,
+                                SENDMSG_QUEUE,
                                 PERSIST_LAST_AUDIBLE,
                                 device,
                                 s,
@@ -606,7 +606,7 @@
                 // to persist). Do not change volume if stream is muted.
                 sendMsg(mAudioHandler,
                         MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_NOOP,
+                        SENDMSG_QUEUE,
                         device,
                         0,
                         streamState,
@@ -746,7 +746,7 @@
                 // Post a persist volume msg
                 sendMsg(mAudioHandler,
                         MSG_PERSIST_VOLUME,
-                        SENDMSG_REPLACE,
+                        SENDMSG_QUEUE,
                         PERSIST_LAST_AUDIBLE,
                         device,
                         streamState,
@@ -758,7 +758,7 @@
                 // to persist).
                 sendMsg(mAudioHandler,
                         MSG_SET_DEVICE_VOLUME,
-                        SENDMSG_NOOP,
+                        SENDMSG_QUEUE,
                         device,
                         0,
                         streamState,
@@ -2208,7 +2208,7 @@
                                     }
                                     sendMsg(mAudioHandler,
                                             MSG_SET_ALL_VOLUMES,
-                                            SENDMSG_NOOP,
+                                            SENDMSG_QUEUE,
                                             0,
                                             0,
                                             VolumeStreamState.this, 0);
@@ -2252,7 +2252,7 @@
                                         }
                                         sendMsg(mAudioHandler,
                                                 MSG_SET_ALL_VOLUMES,
-                                                SENDMSG_NOOP,
+                                                SENDMSG_QUEUE,
                                                 0,
                                                 0,
                                                 VolumeStreamState.this, 0);
@@ -2350,7 +2350,7 @@
             // Post a persist volume msg
             sendMsg(mAudioHandler,
                     MSG_PERSIST_VOLUME,
-                    SENDMSG_REPLACE,
+                    SENDMSG_QUEUE,
                     PERSIST_CURRENT|PERSIST_LAST_AUDIBLE,
                     device,
                     streamState,
diff --git a/media/java/android/media/audiofx/Visualizer.java b/media/java/android/media/audiofx/Visualizer.java
index bcf7b89..91d0add 100755
--- a/media/java/android/media/audiofx/Visualizer.java
+++ b/media/java/android/media/audiofx/Visualizer.java
@@ -84,6 +84,7 @@
     // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
     private static final int NATIVE_EVENT_PCM_CAPTURE = 0;
     private static final int NATIVE_EVENT_FFT_CAPTURE = 1;
+    private static final int NATIVE_EVENT_SERVER_DIED = 2;
 
     // Error codes:
     /**
@@ -147,6 +148,10 @@
      *  PCM and FFT capture listener registered by client
      */
     private OnDataCaptureListener mCaptureListener = null;
+    /**
+     *  Server Died listener registered by client
+     */
+    private OnServerDiedListener mServerDiedListener = null;
 
     // accessed by native methods
     private int mNativeVisualizer;
@@ -396,6 +401,9 @@
     public interface OnDataCaptureListener  {
         /**
          * Method called when a new waveform capture is available.
+         * <p>Data in the waveform buffer is valid only within the scope of the callback.
+         * Applications which needs access to the waveform data after returning from the callback
+         * should make a copy of the data instead of holding a reference.
          * @param visualizer Visualizer object on which the listener is registered.
          * @param waveform array of bytes containing the waveform representation.
          * @param samplingRate sampling rate of the audio visualized.
@@ -404,6 +412,9 @@
 
         /**
          * Method called when a new frequency capture is available.
+         * <p>Data in the fft buffer is valid only within the scope of the callback.
+         * Applications which needs access to the fft data after returning from the callback
+         * should make a copy of the data instead of holding a reference.
          * @param visualizer Visualizer object on which the listener is registered.
          * @param fft array of bytes containing the frequency representation.
          * @param samplingRate sampling rate of the audio visualized.
@@ -452,6 +463,43 @@
     }
 
     /**
+     * @hide
+     *
+     * The OnServerDiedListener interface defines a method called by the Visualizer to indicate that
+     * the connection to the native media server has been broken and that the Visualizer object will
+     * need to be released and re-created.
+     * The client application can implement this interface and register the listener with the
+     * {@link #setServerDiedListener(OnServerDiedListener)} method.
+     */
+    public interface OnServerDiedListener  {
+        /**
+         * @hide
+         *
+         * Method called when the native media server has died.
+         * <p>If the native media server encounters a fatal error and needs to restart, the binder
+         * connection from the {@link #Visualizer} to the media server will be broken.  Data capture
+         * callbacks will stop happening, and client initiated calls to the {@link #Visualizer}
+         * instance will fail with the error code {@link #DEAD_OBJECT}.  To restore functionality,
+         * clients should {@link #release()} their old visualizer and create a new instance.
+         */
+        void onServerDied();
+    }
+
+    /**
+     * @hide
+     *
+     * Registers an OnServerDiedListener interface.
+     * <p>Call this method with a null listener to stop receiving server death notifications.
+     * @return {@link #SUCCESS} in case of success,
+     */
+    public int setServerDiedListener(OnServerDiedListener listener) {
+        synchronized (mListenerLock) {
+            mServerDiedListener = listener;
+        }
+        return SUCCESS;
+    }
+
+    /**
      * Helper class to handle the forwarding of native events to the appropriate listeners
      */
     private class NativeEventHandler extends Handler
@@ -463,11 +511,7 @@
             mVisualizer = v;
         }
 
-        @Override
-        public void handleMessage(Message msg) {
-            if (mVisualizer == null) {
-                return;
-            }
+        private void handleCaptureMessage(Message msg) {
             OnDataCaptureListener l = null;
             synchronized (mListenerLock) {
                 l = mVisualizer.mCaptureListener;
@@ -476,6 +520,7 @@
             if (l != null) {
                 byte[] data = (byte[])msg.obj;
                 int samplingRate = msg.arg1;
+
                 switch(msg.what) {
                 case NATIVE_EVENT_PCM_CAPTURE:
                     l.onWaveFormDataCapture(mVisualizer, data, samplingRate);
@@ -484,11 +529,41 @@
                     l.onFftDataCapture(mVisualizer, data, samplingRate);
                     break;
                 default:
-                    Log.e(TAG,"Unknown native event: "+msg.what);
+                    Log.e(TAG,"Unknown native event in handleCaptureMessge: "+msg.what);
                     break;
                 }
             }
         }
+
+        private void handleServerDiedMessage(Message msg) {
+            OnServerDiedListener l = null;
+            synchronized (mListenerLock) {
+                l = mVisualizer.mServerDiedListener;
+            }
+
+            if (l != null)
+                l.onServerDied();
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (mVisualizer == null) {
+                return;
+            }
+
+            switch(msg.what) {
+            case NATIVE_EVENT_PCM_CAPTURE:
+            case NATIVE_EVENT_FFT_CAPTURE:
+                handleCaptureMessage(msg);
+                break;
+            case NATIVE_EVENT_SERVER_DIED:
+                handleServerDiedMessage(msg);
+                break;
+            default:
+                Log.e(TAG,"Unknown native event: "+msg.what);
+                break;
+            }
+        }
     }
 
     //---------------------------------------------------------
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index ecd4d07..f015afb 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -23,6 +23,7 @@
 #include <nativehelper/jni.h>
 #include <nativehelper/JNIHelp.h>
 #include <android_runtime/AndroidRuntime.h>
+#include <utils/threads.h>
 #include "media/Visualizer.h"
 
 using namespace android;
@@ -38,6 +39,7 @@
 
 #define NATIVE_EVENT_PCM_CAPTURE                0
 #define NATIVE_EVENT_FFT_CAPTURE                1
+#define NATIVE_EVENT_SERVER_DIED                2
 
 // ----------------------------------------------------------------------------
 static const char* const kClassPathName = "android/media/audiofx/Visualizer";
@@ -54,6 +56,43 @@
 struct visualizer_callback_cookie {
     jclass      visualizer_class;  // Visualizer class
     jobject     visualizer_ref;    // Visualizer object instance
+
+    // Lazily allocated arrays used to hold callback data provided to java
+    // applications.  These arrays are allocated during the first callback and
+    // reallocated when the size of the callback data changes.  Allocating on
+    // demand and saving the arrays means that applications cannot safely hold a
+    // reference to the provided data (they need to make a copy if they want to
+    // hold onto outside of the callback scope), but it avoids GC thrash caused
+    // by constantly allocating and releasing arrays to hold callback data.
+    Mutex       callback_data_lock;
+    jbyteArray  waveform_data;
+    jbyteArray  fft_data;
+
+    visualizer_callback_cookie() {
+        waveform_data = NULL;
+        fft_data = NULL;
+    }
+
+    ~visualizer_callback_cookie() {
+        cleanupBuffers();
+    }
+
+    void cleanupBuffers() {
+        AutoMutex lock(&callback_data_lock);
+        if (waveform_data || fft_data) {
+            JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+            if (waveform_data) {
+                env->DeleteGlobalRef(waveform_data);
+                waveform_data = NULL;
+            }
+
+            if (fft_data) {
+                env->DeleteGlobalRef(fft_data);
+                fft_data = NULL;
+            }
+        }
+    }
  };
 
 // ----------------------------------------------------------------------------
@@ -66,7 +105,6 @@
 
     ~visualizerJniStorage() {
     }
-
 };
 
 
@@ -93,6 +131,26 @@
 
 
 // ----------------------------------------------------------------------------
+static void ensureArraySize(JNIEnv *env, jbyteArray *array, uint32_t size) {
+    if (NULL != *array) {
+        uint32_t len = env->GetArrayLength(*array);
+        if (len == size)
+            return;
+
+        env->DeleteGlobalRef(*array);
+        *array = NULL;
+    }
+
+    jbyteArray localRef = env->NewByteArray(size);
+    if (NULL != localRef) {
+        // Promote to global ref.
+        *array = (jbyteArray)env->NewGlobalRef(localRef);
+
+        // Release our (now pointless) local ref.
+        env->DeleteLocalRef(localRef);
+    }
+}
+
 static void captureCallback(void* user,
         uint32_t waveformSize,
         uint8_t *waveform,
@@ -106,6 +164,7 @@
 
     visualizer_callback_cookie *callbackInfo = (visualizer_callback_cookie *)user;
     JNIEnv *env = AndroidRuntime::getJNIEnv();
+    AutoMutex lock(&callbackInfo->callback_data_lock);
 
     ALOGV("captureCallback: callbackInfo %p, visualizer_ref %p visualizer_class %p",
             callbackInfo,
@@ -118,7 +177,11 @@
     }
 
     if (waveformSize != 0 && waveform != NULL) {
-        jbyteArray jArray = env->NewByteArray(waveformSize);
+        jbyteArray jArray;
+
+        ensureArraySize(env, &callbackInfo->waveform_data, waveformSize);
+        jArray = callbackInfo->waveform_data;
+
         if (jArray != NULL) {
             jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
             memcpy(nArray, waveform, waveformSize);
@@ -131,12 +194,15 @@
                 samplingrate,
                 0,
                 jArray);
-            env->DeleteLocalRef(jArray);
         }
     }
 
     if (fftSize != 0 && fft != NULL) {
-        jbyteArray jArray = env->NewByteArray(fftSize);
+        jbyteArray jArray;
+
+        ensureArraySize(env, &callbackInfo->fft_data, fftSize);
+        jArray = callbackInfo->fft_data;
+
         if (jArray != NULL) {
             jbyte *nArray = env->GetByteArrayElements(jArray, NULL);
             memcpy(nArray, fft, fftSize);
@@ -149,7 +215,6 @@
                 samplingrate,
                 0,
                 jArray);
-            env->DeleteLocalRef(jArray);
         }
     }
 
@@ -220,6 +285,23 @@
 
 }
 
+static void android_media_visualizer_effect_callback(int32_t event,
+                                                     void *user,
+                                                     void *info) {
+    if ((event == AudioEffect::EVENT_ERROR) &&
+        (*((status_t*)info) == DEAD_OBJECT)) {
+        visualizerJniStorage* lpJniStorage = (visualizerJniStorage*)user;
+        visualizer_callback_cookie* callbackInfo = &lpJniStorage->mCallbackData;
+        JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+        env->CallStaticVoidMethod(
+            callbackInfo->visualizer_class,
+            fields.midPostNativeEvent,
+            callbackInfo->visualizer_ref,
+            NATIVE_EVENT_SERVER_DIED,
+            0, 0, 0);
+    }
+}
 
 static jint
 android_media_visualizer_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
@@ -255,8 +337,8 @@
 
     // create the native Visualizer object
     lpVisualizer = new Visualizer(0,
-                                  NULL,
-                                  NULL,
+                                  android_media_visualizer_effect_callback,
+                                  lpJniStorage,
                                   sessionId);
     if (lpVisualizer == NULL) {
         ALOGE("Error creating Visualizer");
@@ -345,7 +427,17 @@
         return VISUALIZER_ERROR_NO_INIT;
     }
 
-    return translateError(lpVisualizer->setEnabled(enabled));
+    jint retVal = translateError(lpVisualizer->setEnabled(enabled));
+
+    if (!enabled) {
+        visualizerJniStorage* lpJniStorage = (visualizerJniStorage *)env->GetIntField(
+            thiz, fields.fidJniData);
+
+        if (NULL != lpJniStorage)
+            lpJniStorage->mCallbackData.cleanupBuffers();
+    }
+
+    return retVal;
 }
 
 static jboolean
diff --git a/media/libaah_rtp/Android.mk b/media/libaah_rtp/Android.mk
new file mode 100644
index 0000000..54fd9ec
--- /dev/null
+++ b/media/libaah_rtp/Android.mk
@@ -0,0 +1,40 @@
+LOCAL_PATH:= $(call my-dir)
+#
+# libaah_rtp
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaah_rtp
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+    aah_decoder_pump.cpp \
+    aah_rx_player.cpp \
+    aah_rx_player_core.cpp \
+    aah_rx_player_ring_buffer.cpp \
+    aah_rx_player_substream.cpp \
+    aah_tx_packet.cpp \
+    aah_tx_player.cpp \
+    aah_tx_sender.cpp \
+    pipe_event.cpp
+
+LOCAL_C_INCLUDES := \
+    frameworks/base/include \
+    frameworks/base/include/media/stagefright/openmax \
+    frameworks/base/media \
+    frameworks/base/media/libstagefright
+
+LOCAL_SHARED_LIBRARIES := \
+    libcommon_time_client \
+    libbinder \
+    libmedia \
+    libstagefright \
+    libstagefright_foundation \
+    libutils
+
+LOCAL_LDLIBS := \
+    -lpthread
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/media/libaah_rtp/aah_decoder_pump.cpp b/media/libaah_rtp/aah_decoder_pump.cpp
new file mode 100644
index 0000000..72fe43b
--- /dev/null
+++ b/media/libaah_rtp/aah_decoder_pump.cpp
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <poll.h>
+#include <pthread.h>
+
+#include <common_time/cc_helper.h>
+#include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
+#include <utils/Timers.h>
+#include <utils/threads.h>
+
+#include "aah_decoder_pump.h"
+
+namespace android {
+
+static const long long kLongDecodeErrorThreshold = 1000000ll;
+static const uint32_t kMaxLongErrorsBeforeFatal = 3;
+static const uint32_t kMaxErrorsBeforeFatal = 60;
+
+AAH_DecoderPump::AAH_DecoderPump(OMXClient& omx)
+    : omx_(omx)
+    , thread_status_(OK)
+    , renderer_(NULL)
+    , last_queued_pts_valid_(false)
+    , last_queued_pts_(0)
+    , last_ts_transform_valid_(false)
+    , last_volume_(0xFF) {
+    thread_ = new ThreadWrapper(this);
+}
+
+AAH_DecoderPump::~AAH_DecoderPump() {
+    shutdown();
+}
+
+status_t AAH_DecoderPump::initCheck() {
+    if (thread_ == NULL) {
+        ALOGE("Failed to allocate thread");
+        return NO_MEMORY;
+    }
+
+    return OK;
+}
+
+status_t AAH_DecoderPump::queueForDecode(MediaBuffer* buf) {
+    if (NULL == buf) {
+        return BAD_VALUE;
+    }
+
+    if (OK != thread_status_) {
+        return thread_status_;
+    }
+
+    {   // Explicit scope for AutoMutex pattern.
+        AutoMutex lock(&thread_lock_);
+        in_queue_.push_back(buf);
+    }
+
+    thread_cond_.signal();
+
+    return OK;
+}
+
+void AAH_DecoderPump::queueToRenderer(MediaBuffer* decoded_sample) {
+    Mutex::Autolock lock(&render_lock_);
+    sp<MetaData> meta;
+    int64_t ts;
+    status_t res;
+
+    // Fetch the metadata and make sure the sample has a timestamp.  We
+    // cannot render samples which are missing PTSs.
+    meta = decoded_sample->meta_data();
+    if ((meta == NULL) || (!meta->findInt64(kKeyTime, &ts))) {
+        ALOGV("Decoded sample missing timestamp, cannot render.");
+        CHECK(false);
+    } else {
+        // If we currently are not holding on to a renderer, go ahead and
+        // make one now.
+        if (NULL == renderer_) {
+            renderer_ = new TimedAudioTrack();
+            if (NULL != renderer_) {
+                int frameCount;
+                AudioTrack::getMinFrameCount(&frameCount,
+                        AUDIO_STREAM_DEFAULT,
+                        static_cast<int>(format_sample_rate_));
+                int ch_format = (format_channels_ == 1)
+                    ? AUDIO_CHANNEL_OUT_MONO
+                    : AUDIO_CHANNEL_OUT_STEREO;
+
+                res = renderer_->set(AUDIO_STREAM_DEFAULT,
+                        format_sample_rate_,
+                        AUDIO_FORMAT_PCM_16_BIT,
+                        ch_format,
+                        frameCount);
+                if (res != OK) {
+                    ALOGE("Failed to setup audio renderer. (res = %d)", res);
+                    delete renderer_;
+                    renderer_ = NULL;
+                } else {
+                    CHECK(last_ts_transform_valid_);
+
+                    res = renderer_->setMediaTimeTransform(
+                            last_ts_transform_, TimedAudioTrack::COMMON_TIME);
+                    if (res != NO_ERROR) {
+                        ALOGE("Failed to set media time transform on AudioTrack"
+                              " (res = %d)", res);
+                        delete renderer_;
+                        renderer_ = NULL;
+                    } else {
+                        float volume = static_cast<float>(last_volume_)
+                                     / 255.0f;
+                        if (renderer_->setVolume(volume, volume) != OK) {
+                            ALOGW("%s: setVolume failed", __FUNCTION__);
+                        }
+
+                        renderer_->start();
+                    }
+                }
+            } else {
+                ALOGE("Failed to allocate AudioTrack to use as a renderer.");
+            }
+        }
+
+        if (NULL != renderer_) {
+            uint8_t* decoded_data =
+                reinterpret_cast<uint8_t*>(decoded_sample->data());
+            uint32_t decoded_amt  = decoded_sample->range_length();
+            decoded_data += decoded_sample->range_offset();
+
+            sp<IMemory> pcm_payload;
+            res = renderer_->allocateTimedBuffer(decoded_amt, &pcm_payload);
+            if (res != OK) {
+                ALOGE("Failed to allocate %d byte audio track buffer."
+                      " (res = %d)", decoded_amt, res);
+            } else {
+                memcpy(pcm_payload->pointer(), decoded_data, decoded_amt);
+
+                res = renderer_->queueTimedBuffer(pcm_payload, ts);
+                if (res != OK) {
+                    ALOGE("Failed to queue %d byte audio track buffer with media"
+                          " PTS %lld. (res = %d)", decoded_amt, ts, res);
+                } else {
+                    last_queued_pts_valid_ = true;
+                    last_queued_pts_ = ts;
+                }
+            }
+
+        } else {
+            ALOGE("No renderer, dropping audio payload.");
+        }
+    }
+}
+
+void AAH_DecoderPump::stopAndCleanupRenderer() {
+    if (NULL == renderer_) {
+        return;
+    }
+
+    renderer_->stop();
+    delete renderer_;
+    renderer_ = NULL;
+}
+
+void AAH_DecoderPump::setRenderTSTransform(const LinearTransform& trans) {
+    Mutex::Autolock lock(&render_lock_);
+
+    if (last_ts_transform_valid_ && !memcmp(&trans,
+                                            &last_ts_transform_,
+                                            sizeof(trans))) {
+        return;
+    }
+
+    last_ts_transform_       = trans;
+    last_ts_transform_valid_ = true;
+
+    if (NULL != renderer_) {
+        status_t res = renderer_->setMediaTimeTransform(
+                last_ts_transform_, TimedAudioTrack::COMMON_TIME);
+        if (res != NO_ERROR) {
+            ALOGE("Failed to set media time transform on AudioTrack"
+                  " (res = %d)", res);
+        }
+    }
+}
+
+void AAH_DecoderPump::setRenderVolume(uint8_t volume) {
+    Mutex::Autolock lock(&render_lock_);
+
+    if (volume == last_volume_) {
+        return;
+    }
+
+    last_volume_ = volume;
+    if (renderer_ != NULL) {
+        float volume = static_cast<float>(last_volume_) / 255.0f;
+        if (renderer_->setVolume(volume, volume) != OK) {
+            ALOGW("%s: setVolume failed", __FUNCTION__);
+        }
+    }
+}
+
+// isAboutToUnderflow is something of a hack used to figure out when it might be
+// time to give up on trying to fill in a gap in the RTP sequence and simply
+// move on with a discontinuity.  If we had perfect knowledge of when we were
+// going to underflow, it would not be a hack, but unfortunately we do not.
+// Right now, we just take the PTS of the last sample queued, and check to see
+// if its presentation time is within kAboutToUnderflowThreshold from now.  If
+// it is, then we say that we are about to underflow.  This decision is based on
+// two (possibly invalid) assumptions.
+//
+// 1) The transmitter is leading the clock by more than
+//    kAboutToUnderflowThreshold.
+// 2) The delta between the PTS of the last sample queued and the next sample
+//    is less than the transmitter's clock lead amount.
+//
+// Right now, the default transmitter lead time is 1 second, which is a pretty
+// large number and greater than the 50mSec that kAboutToUnderflowThreshold is
+// currently set to.  This should satisfy assumption #1 for now, but changes to
+// the transmitter clock lead time could effect this.
+//
+// For non-sparse streams with a homogeneous sample rate (the vast majority of
+// streams in the world), the delta between any two adjacent PTSs will always be
+// the homogeneous sample period.  It is very uncommon to see a sample period
+// greater than the 1 second clock lead we are currently using, and you
+// certainly will not see it in an MP3 file which should satisfy assumption #2.
+// Sparse audio streams (where no audio is transmitted for long periods of
+// silence) and extremely low framerate video stream (like an MPEG-2 slideshow
+// or the video stream for a pay TV audio channel) are examples of streams which
+// might violate assumption #2.
+bool AAH_DecoderPump::isAboutToUnderflow(int64_t threshold) {
+    Mutex::Autolock lock(&render_lock_);
+
+    // If we have never queued anything to the decoder, we really don't know if
+    // we are going to underflow or not.
+    if (!last_queued_pts_valid_ || !last_ts_transform_valid_) {
+        return false;
+    }
+
+    // Don't have access to Common Time?  If so, then things are Very Bad
+    // elsewhere in the system; it pretty much does not matter what we do here.
+    // Since we cannot really tell if we are about to underflow or not, its
+    // probably best to assume that we are not and proceed accordingly.
+    int64_t tt_now;
+    if (OK != cc_helper_.getCommonTime(&tt_now)) {
+        return false;
+    }
+
+    // Transform from media time to common time.
+    int64_t last_queued_pts_tt;
+    if (!last_ts_transform_.doForwardTransform(last_queued_pts_,
+                &last_queued_pts_tt)) {
+        return false;
+    }
+
+    // Check to see if we are underflowing.
+    return ((tt_now + threshold - last_queued_pts_tt) > 0);
+}
+
+void* AAH_DecoderPump::workThread() {
+    // No need to lock when accessing decoder_ from the thread.  The
+    // implementation of init and shutdown ensure that other threads never touch
+    // decoder_ while the work thread is running.
+    CHECK(decoder_ != NULL);
+    CHECK(format_  != NULL);
+
+    // Start the decoder and note its result code.  If something goes horribly
+    // wrong, callers of queueForDecode and getOutput will be able to detect
+    // that the thread encountered a fatal error and shut down by examining
+    // thread_status_.
+    thread_status_ = decoder_->start(format_.get());
+    if (OK != thread_status_) {
+        ALOGE("AAH_DecoderPump's work thread failed to start decoder (res = %d)",
+                thread_status_);
+        return NULL;
+    }
+
+    DurationTimer decode_timer;
+    uint32_t consecutive_long_errors = 0;
+    uint32_t consecutive_errors = 0;
+
+    while (!thread_->exitPending()) {
+        status_t res;
+        MediaBuffer* bufOut = NULL;
+
+        decode_timer.start();
+        res = decoder_->read(&bufOut);
+        decode_timer.stop();
+
+        if (res == INFO_FORMAT_CHANGED) {
+            // Format has changed.  Destroy our current renderer so that a new
+            // one can be created during queueToRenderer with the proper format.
+            //
+            // TODO : In order to transition seamlessly, we should change this
+            // to put the old renderer in a queue to play out completely before
+            // we destroy it.  We can still create a new renderer, the timed
+            // nature of the renderer should ensure a seamless splice.
+            stopAndCleanupRenderer();
+            res = OK;
+        }
+
+        // Try to be a little nuanced in our handling of actual decode errors.
+        // Errors could happen because of minor stream corruption or because of
+        // transient resource limitations.  In these cases, we would rather drop
+        // a little bit of output and ride out the unpleasantness then throw up
+        // our hands and abort everything.
+        //
+        // OTOH - When things are really bad (like we have a non-transient
+        // resource or bookkeeping issue, or the stream being fed to us is just
+        // complete and total garbage) we really want to terminate playback and
+        // raise an error condition all the way up to the application level so
+        // they can deal with it.
+        //
+        // Unfortunately, the error codes returned by the decoder can be a
+        // little non-specific.  For example, if an OMXCodec times out
+        // attempting to obtain an output buffer, the error we get back is a
+        // generic -1.  Try to distinguish between this resource timeout error
+        // and ES corruption error by timing how long the decode operation
+        // takes.  Maintain accounting for both errors and "long errors".  If we
+        // get more than a certain number consecutive errors of either type,
+        // consider it fatal and shutdown (which will cause the error to
+        // propagate all of the way up to the application level).  The threshold
+        // for "long errors" is deliberately much lower than that of normal
+        // decode errors, both because of how long they take to happen and
+        // because they generally indicate resource limitation errors which are
+        // unlikely to go away in pathologically bad cases (in contrast to
+        // stream corruption errors which might happen 20 times in a row and
+        // then be suddenly OK again)
+        if (res != OK) {
+            consecutive_errors++;
+            if (decode_timer.durationUsecs() >= kLongDecodeErrorThreshold)
+                consecutive_long_errors++;
+
+            CHECK(NULL == bufOut);
+
+            ALOGW("%s: Failed to decode data (res = %d)",
+                    __PRETTY_FUNCTION__, res);
+
+            if ((consecutive_errors      >= kMaxErrorsBeforeFatal) ||
+                (consecutive_long_errors >= kMaxLongErrorsBeforeFatal)) {
+                ALOGE("%s: Maximum decode error threshold has been reached."
+                      " There have been %d consecutive decode errors, and %d"
+                      " consecutive decode operations which resulted in errors"
+                      " and took more than %lld uSec to process.  The last"
+                      " decode operation took %lld uSec.",
+                      __PRETTY_FUNCTION__,
+                      consecutive_errors, consecutive_long_errors,
+                      kLongDecodeErrorThreshold, decode_timer.durationUsecs());
+                thread_status_ = res;
+                break;
+            }
+
+            continue;
+        }
+
+        if (NULL == bufOut) {
+            ALOGW("%s: Successful decode, but no buffer produced",
+                    __PRETTY_FUNCTION__);
+            continue;
+        }
+
+        // Successful decode (with actual output produced).  Clear the error
+        // counters.
+        consecutive_errors = 0;
+        consecutive_long_errors = 0;
+
+        queueToRenderer(bufOut);
+        bufOut->release();
+    }
+
+    decoder_->stop();
+    stopAndCleanupRenderer();
+
+    return NULL;
+}
+
+status_t AAH_DecoderPump::init(const sp<MetaData>& params) {
+    Mutex::Autolock lock(&init_lock_);
+
+    if (decoder_ != NULL) {
+        // already inited
+        return OK;
+    }
+
+    if (params == NULL) {
+        return BAD_VALUE;
+    }
+
+    if (!params->findInt32(kKeyChannelCount, &format_channels_)) {
+        return BAD_VALUE;
+    }
+
+    if (!params->findInt32(kKeySampleRate, &format_sample_rate_)) {
+        return BAD_VALUE;
+    }
+
+    CHECK(OK == thread_status_);
+    CHECK(decoder_ == NULL);
+
+    status_t ret_val = UNKNOWN_ERROR;
+
+    // Cache the format and attempt to create the decoder.
+    format_  = params;
+    decoder_ = OMXCodec::Create(
+            omx_.interface(),       // IOMX Handle
+            format_,                // Metadata for substream (indicates codec)
+            false,                  // Make a decoder, not an encoder
+            sp<MediaSource>(this)); // We will be the source for this codec.
+
+    if (decoder_ == NULL) {
+      ALOGE("Failed to allocate decoder in %s", __PRETTY_FUNCTION__);
+      goto bailout;
+    }
+
+    // Fire up the pump thread.  It will take care of starting and stopping the
+    // decoder.
+    ret_val = thread_->run("aah_decode_pump", ANDROID_PRIORITY_AUDIO);
+    if (OK != ret_val) {
+        ALOGE("Failed to start work thread in %s (res = %d)",
+                __PRETTY_FUNCTION__, ret_val);
+        goto bailout;
+    }
+
+bailout:
+    if (OK != ret_val) {
+        decoder_ = NULL;
+        format_  = NULL;
+    }
+
+    return OK;
+}
+
+status_t AAH_DecoderPump::shutdown() {
+    Mutex::Autolock lock(&init_lock_);
+    return shutdown_l();
+}
+
+status_t AAH_DecoderPump::shutdown_l() {
+    thread_->requestExit();
+    thread_cond_.signal();
+    thread_->requestExitAndWait();
+
+    for (MBQueue::iterator iter = in_queue_.begin();
+         iter != in_queue_.end();
+         ++iter) {
+        (*iter)->release();
+    }
+    in_queue_.clear();
+
+    last_queued_pts_valid_   = false;
+    last_ts_transform_valid_ = false;
+    last_volume_             = 0xFF;
+    thread_status_           = OK;
+
+    decoder_ = NULL;
+    format_  = NULL;
+
+    return OK;
+}
+
+status_t AAH_DecoderPump::read(MediaBuffer **buffer,
+                               const ReadOptions *options) {
+    if (!buffer) {
+        return BAD_VALUE;
+    }
+
+    *buffer = NULL;
+
+    // While its not time to shut down, and we have no data to process, wait.
+    AutoMutex lock(&thread_lock_);
+    while (!thread_->exitPending() && in_queue_.empty())
+        thread_cond_.wait(thread_lock_);
+
+    // At this point, if its not time to shutdown then we must have something to
+    // process.  Go ahead and pop the front of the queue for processing.
+    if (!thread_->exitPending()) {
+        CHECK(!in_queue_.empty());
+
+        *buffer = *(in_queue_.begin());
+        in_queue_.erase(in_queue_.begin());
+    }
+
+    // If we managed to get a buffer, then everything must be OK.  If not, then
+    // we must be shutting down.
+    return (NULL == *buffer) ? INVALID_OPERATION : OK;
+}
+
+AAH_DecoderPump::ThreadWrapper::ThreadWrapper(AAH_DecoderPump* owner)
+    : Thread(false /* canCallJava*/ )
+    , owner_(owner) {
+}
+
+bool AAH_DecoderPump::ThreadWrapper::threadLoop() {
+    CHECK(NULL != owner_);
+    owner_->workThread();
+    return false;
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_decoder_pump.h b/media/libaah_rtp/aah_decoder_pump.h
new file mode 100644
index 0000000..f5a6529
--- /dev/null
+++ b/media/libaah_rtp/aah_decoder_pump.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DECODER_PUMP_H__
+#define __DECODER_PUMP_H__
+
+#include <pthread.h>
+
+#include <common_time/cc_helper.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/LinearTransform.h>
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class MetaData;
+class OMXClient;
+class TimedAudioTrack;
+
+class AAH_DecoderPump : public MediaSource {
+  public:
+    explicit AAH_DecoderPump(OMXClient& omx);
+    status_t initCheck();
+
+    status_t queueForDecode(MediaBuffer* buf);
+
+    status_t init(const sp<MetaData>& params);
+    status_t shutdown();
+
+    void setRenderTSTransform(const LinearTransform& trans);
+    void setRenderVolume(uint8_t volume);
+    bool isAboutToUnderflow(int64_t threshold);
+    bool getStatus() const { return thread_status_; }
+
+    // MediaSource methods
+    virtual status_t     start(MetaData *params) { return OK; }
+    virtual sp<MetaData> getFormat() { return format_; }
+    virtual status_t     stop() { return OK; }
+    virtual status_t     read(MediaBuffer **buffer,
+                              const ReadOptions *options);
+
+  protected:
+    virtual ~AAH_DecoderPump();
+
+  private:
+    class ThreadWrapper : public Thread {
+      public:
+        friend class AAH_DecoderPump;
+        explicit ThreadWrapper(AAH_DecoderPump* owner);
+
+      private:
+        virtual bool threadLoop();
+        AAH_DecoderPump* owner_;
+
+        DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
+    };
+
+    void* workThread();
+    virtual status_t shutdown_l();
+    void queueToRenderer(MediaBuffer* decoded_sample);
+    void stopAndCleanupRenderer();
+
+    sp<MetaData>        format_;
+    int32_t             format_channels_;
+    int32_t             format_sample_rate_;
+
+    sp<MediaSource>     decoder_;
+    OMXClient&          omx_;
+    Mutex               init_lock_;
+
+    sp<ThreadWrapper>   thread_;
+    Condition           thread_cond_;
+    Mutex               thread_lock_;
+    status_t            thread_status_;
+
+    Mutex               render_lock_;
+    TimedAudioTrack*    renderer_;
+    bool                last_queued_pts_valid_;
+    int64_t             last_queued_pts_;
+    bool                last_ts_transform_valid_;
+    LinearTransform     last_ts_transform_;
+    uint8_t             last_volume_;
+    CCHelper            cc_helper_;
+
+    // protected by the thread_lock_
+    typedef List<MediaBuffer*> MBQueue;
+    MBQueue in_queue_;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AAH_DecoderPump);
+};
+
+}  // namespace android
+#endif  // __DECODER_PUMP_H__
diff --git a/media/libaah_rtp/aah_rx_player.cpp b/media/libaah_rtp/aah_rx_player.cpp
new file mode 100644
index 0000000..9dd79fd
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+
+#include <binder/IServiceManager.h>
+#include <media/MediaPlayerInterface.h>
+#include <utils/Log.h>
+
+#include "aah_rx_player.h"
+
+namespace android {
+
+const uint32_t AAH_RXPlayer::kRTPRingBufferSize = 1 << 10;
+
+sp<MediaPlayerBase> createAAH_RXPlayer() {
+    sp<MediaPlayerBase> ret = new AAH_RXPlayer();
+    return ret;
+}
+
+AAH_RXPlayer::AAH_RXPlayer()
+        : ring_buffer_(kRTPRingBufferSize)
+        , substreams_(NULL) {
+    thread_wrapper_ = new ThreadWrapper(*this);
+
+    is_playing_          = false;
+    multicast_joined_    = false;
+    transmitter_known_   = false;
+    current_epoch_known_ = false;
+    data_source_set_     = false;
+    sock_fd_             = -1;
+
+    substreams_.setCapacity(4);
+
+    memset(&listen_addr_,      0, sizeof(listen_addr_));
+    memset(&transmitter_addr_, 0, sizeof(transmitter_addr_));
+
+    fetchAudioFlinger();
+}
+
+AAH_RXPlayer::~AAH_RXPlayer() {
+    reset_l();
+    CHECK(substreams_.size() == 0);
+    omx_.disconnect();
+}
+
+status_t AAH_RXPlayer::initCheck() {
+    if (thread_wrapper_ == NULL) {
+        ALOGE("Failed to allocate thread wrapper!");
+        return NO_MEMORY;
+    }
+
+    if (!ring_buffer_.initCheck()) {
+        ALOGE("Failed to allocate reassembly ring buffer!");
+        return NO_MEMORY;
+    }
+
+    // Check for the presense of the common time service by attempting to query
+    // for CommonTime's frequency.  If we get an error back, we cannot talk to
+    // the service at all and should abort now.
+    status_t res;
+    uint64_t freq;
+    res = cc_helper_.getCommonFreq(&freq);
+    if (OK != res) {
+        ALOGE("Failed to connect to common time service!");
+        return res;
+    }
+
+    return omx_.connect();
+}
+
+status_t AAH_RXPlayer::setDataSource(
+        const char *url,
+        const KeyedVector<String8, String8> *headers) {
+    AutoMutex api_lock(&api_lock_);
+    uint32_t a, b, c, d;
+    uint16_t port;
+
+    if (data_source_set_) {
+        return INVALID_OPERATION;
+    }
+
+    if (NULL == url) {
+        return BAD_VALUE;
+    }
+
+    if (5 != sscanf(url, "%*[^:/]://%u.%u.%u.%u:%hu", &a, &b, &c, &d, &port)) {
+        ALOGE("Failed to parse URL \"%s\"", url);
+        return BAD_VALUE;
+    }
+
+    if ((a > 255) || (b > 255) || (c > 255) || (d > 255) || (port == 0)) {
+        ALOGE("Bad multicast address \"%s\"", url);
+        return BAD_VALUE;
+    }
+
+    ALOGI("setDataSource :: %u.%u.%u.%u:%hu", a, b, c, d, port);
+
+    a = (a << 24) | (b << 16) | (c <<  8) | d;
+
+    memset(&listen_addr_, 0, sizeof(listen_addr_));
+    listen_addr_.sin_family      = AF_INET;
+    listen_addr_.sin_port        = htons(port);
+    listen_addr_.sin_addr.s_addr = htonl(a);
+    data_source_set_ = true;
+
+    return OK;
+}
+
+status_t AAH_RXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+    return INVALID_OPERATION;
+}
+
+status_t AAH_RXPlayer::setVideoSurface(const sp<Surface>& surface) {
+    return OK;
+}
+
+status_t AAH_RXPlayer::setVideoSurfaceTexture(
+        const sp<ISurfaceTexture>& surfaceTexture) {
+    return OK;
+}
+
+status_t AAH_RXPlayer::prepare() {
+    return OK;
+}
+
+status_t AAH_RXPlayer::prepareAsync() {
+    sendEvent(MEDIA_PREPARED);
+    return OK;
+}
+
+status_t AAH_RXPlayer::start() {
+    AutoMutex api_lock(&api_lock_);
+
+    if (is_playing_) {
+        return OK;
+    }
+
+    status_t res = startWorkThread();
+    is_playing_ = (res == OK);
+    return res;
+}
+
+status_t AAH_RXPlayer::stop() {
+    return pause();
+}
+
+status_t AAH_RXPlayer::pause() {
+    AutoMutex api_lock(&api_lock_);
+    stopWorkThread();
+    CHECK(sock_fd_ < 0);
+    is_playing_ = false;
+    return OK;
+}
+
+bool AAH_RXPlayer::isPlaying() {
+    AutoMutex api_lock(&api_lock_);
+    return is_playing_;
+}
+
+status_t AAH_RXPlayer::seekTo(int msec) {
+    sendEvent(MEDIA_SEEK_COMPLETE);
+    return OK;
+}
+
+status_t AAH_RXPlayer::getCurrentPosition(int *msec) {
+    if (NULL != msec) {
+        *msec = 0;
+    }
+    return OK;
+}
+
+status_t AAH_RXPlayer::getDuration(int *msec) {
+    if (NULL != msec) {
+        *msec = 1;
+    }
+    return OK;
+}
+
+status_t AAH_RXPlayer::reset() {
+    AutoMutex api_lock(&api_lock_);
+    reset_l();
+    return OK;
+}
+
+void AAH_RXPlayer::reset_l() {
+    stopWorkThread();
+    CHECK(sock_fd_ < 0);
+    CHECK(!multicast_joined_);
+    is_playing_ = false;
+    data_source_set_ = false;
+    transmitter_known_ = false;
+    memset(&listen_addr_, 0, sizeof(listen_addr_));
+}
+
+status_t AAH_RXPlayer::setLooping(int loop) {
+    return OK;
+}
+
+player_type AAH_RXPlayer::playerType() {
+    return AAH_RX_PLAYER;
+}
+
+status_t AAH_RXPlayer::setParameter(int key, const Parcel &request) {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_RXPlayer::getParameter(int key, Parcel *reply) {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_RXPlayer::invoke(const Parcel& request, Parcel *reply) {
+    if (!reply) {
+        return BAD_VALUE;
+    }
+
+    int32_t magic;
+    status_t err = request.readInt32(&magic);
+    if (err != OK) {
+        reply->writeInt32(err);
+        return OK;
+    }
+
+    if (magic != 0x12345) {
+        reply->writeInt32(BAD_VALUE);
+        return OK;
+    }
+
+    int32_t methodID;
+    err = request.readInt32(&methodID);
+    if (err != OK) {
+        reply->writeInt32(err);
+        return OK;
+    }
+
+    switch (methodID) {
+        // Get Volume
+        case INVOKE_GET_MASTER_VOLUME: {
+            if (audio_flinger_ != NULL) {
+                reply->writeInt32(OK);
+                reply->writeFloat(audio_flinger_->masterVolume());
+            } else {
+                reply->writeInt32(UNKNOWN_ERROR);
+            }
+        } break;
+
+        // Set Volume
+        case INVOKE_SET_MASTER_VOLUME: {
+            float targetVol = request.readFloat();
+            reply->writeInt32(audio_flinger_->setMasterVolume(targetVol));
+        } break;
+
+        default: return BAD_VALUE;
+    }
+
+    return OK;
+}
+
+void AAH_RXPlayer::fetchAudioFlinger() {
+    if (audio_flinger_ == NULL) {
+        sp<IServiceManager> sm = defaultServiceManager();
+        sp<IBinder> binder;
+        binder = sm->getService(String16("media.audio_flinger"));
+
+        if (binder == NULL) {
+            ALOGW("AAH_RXPlayer failed to fetch handle to audio flinger."
+                  " Master volume control will not be possible.");
+        }
+
+        audio_flinger_ = interface_cast<IAudioFlinger>(binder);
+    }
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_rx_player.h b/media/libaah_rtp/aah_rx_player.h
new file mode 100644
index 0000000..7a1b6e3
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player.h
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAH_RX_PLAYER_H__
+#define __AAH_RX_PLAYER_H__
+
+#include <common_time/cc_helper.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXClient.h>
+#include <netinet/in.h>
+#include <utils/KeyedVector.h>
+#include <utils/LinearTransform.h>
+#include <utils/threads.h>
+
+#include "aah_decoder_pump.h"
+#include "pipe_event.h"
+
+namespace android {
+
+class AAH_RXPlayer : public MediaPlayerInterface {
+  public:
+    AAH_RXPlayer();
+
+    virtual status_t    initCheck();
+    virtual status_t    setDataSource(const char *url,
+                                      const KeyedVector<String8, String8>*
+                                      headers);
+    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
+    virtual status_t    setVideoSurface(const sp<Surface>& surface);
+    virtual status_t    setVideoSurfaceTexture(const sp<ISurfaceTexture>&
+                                               surfaceTexture);
+    virtual status_t    prepare();
+    virtual status_t    prepareAsync();
+    virtual status_t    start();
+    virtual status_t    stop();
+    virtual status_t    pause();
+    virtual bool        isPlaying();
+    virtual status_t    seekTo(int msec);
+    virtual status_t    getCurrentPosition(int *msec);
+    virtual status_t    getDuration(int *msec);
+    virtual status_t    reset();
+    virtual status_t    setLooping(int loop);
+    virtual player_type playerType();
+    virtual status_t    setParameter(int key, const Parcel &request);
+    virtual status_t    getParameter(int key, Parcel *reply);
+    virtual status_t    invoke(const Parcel& request, Parcel *reply);
+
+  protected:
+    virtual ~AAH_RXPlayer();
+
+  private:
+    class ThreadWrapper : public Thread {
+      public:
+        friend class AAH_RXPlayer;
+        explicit ThreadWrapper(AAH_RXPlayer& player)
+            : Thread(false /* canCallJava */ )
+            , player_(player) { }
+
+        virtual bool threadLoop() { return player_.threadLoop(); }
+
+      private:
+        AAH_RXPlayer& player_;
+
+        DISALLOW_EVIL_CONSTRUCTORS(ThreadWrapper);
+    };
+
+#pragma pack(push, 1)
+    // PacketBuffers are structures used by the RX ring buffer.  The ring buffer
+    // is a ring of pointers to PacketBuffer structures which act as variable
+    // length byte arrays and hold the contents of received UDP packets.  Rather
+    // than make this a structure which hold a length and a pointer to another
+    // allocated structure (which would require two allocations), this struct
+    // uses a structure overlay pattern where allocation for the byte array
+    // consists of allocating (arrayLen + sizeof(ssize_t)) bytes of data from
+    // whatever pool/heap the packet buffer pulls from, and then overlaying the
+    // packed PacketBuffer structure on top of the allocation.  The one-byte
+    // array at the end of the structure serves as an offset to the the data
+    // portion of the allocation; packet buffers are never allocated on the
+    // stack or using the new operator.  Instead, the static allocate-byte-array
+    // and destroy methods handle the allocate and overlay pattern.  They also
+    // allow for a potential future optimization where instead of just
+    // allocating blocks from the process global heap and overlaying, the
+    // allocator is replaced with a different implementation (private heap,
+    // free-list, circular buffer, etc) which reduces potential heap
+    // fragmentation issues which might arise from the frequent allocation and
+    // destruction of the received UDP traffic.
+    struct PacketBuffer {
+        ssize_t length_;
+        uint8_t data_[1];
+
+        // TODO : consider changing this to be some form of ring buffer or free
+        // pool system instead of just using the heap in order to avoid heap
+        // fragmentation.
+        static PacketBuffer* allocate(ssize_t length);
+        static void destroy(PacketBuffer* pb);
+
+      private:
+        // Force people to use allocate/destroy instead of new/delete.
+        PacketBuffer() { }
+        ~PacketBuffer() { }
+    };
+
+    struct RetransRequest {
+        uint32_t magic_;
+        uint32_t mcast_ip_;
+        uint16_t mcast_port_;
+        uint16_t start_seq_;
+        uint16_t end_seq_;
+    };
+#pragma pack(pop)
+
+    enum GapStatus {
+        kGS_NoGap = 0,
+        kGS_NormalGap,
+        kGS_FastStartGap,
+    };
+
+    struct SeqNoGap {
+        uint16_t start_seq_;
+        uint16_t end_seq_;
+    };
+
+    class RXRingBuffer {
+      public:
+        explicit RXRingBuffer(uint32_t capacity);
+        ~RXRingBuffer();
+
+        bool initCheck() const { return (ring_ != NULL); }
+        void reset();
+
+        // Push a packet buffer with a given sequence number into the ring
+        // buffer.  pushBuffer will always consume the buffer pushed to it,
+        // either destroying it because it was a duplicate or overflow, or
+        // holding on to it in the ring.  Callers should not hold any references
+        // to PacketBuffers after they have been pushed to the ring.  Returns
+        // false in the case of a serious error (such as ring overflow).
+        // Callers should consider resetting the pipeline entirely in the event
+        // of a serious error.
+        bool pushBuffer(PacketBuffer* buf, uint16_t seq);
+
+        // Fetch the next buffer in the RTP sequence.  Returns NULL if there is
+        // no buffer to fetch.  If a non-NULL PacketBuffer is returned,
+        // is_discon will be set to indicate whether or not this PacketBuffer is
+        // discontiuous with any previously returned packet buffers.  Packet
+        // buffers returned by fetchBuffer are the caller's responsibility; they
+        // must be certain to destroy the buffers when they are done.
+        PacketBuffer* fetchBuffer(bool* is_discon);
+
+        // Returns true and fills out the gap structure if the read pointer of
+        // the ring buffer is currently pointing to a gap which would stall a
+        // fetchBuffer operation.  Returns false if the read pointer is not
+        // pointing to a gap in the sequence currently.
+        GapStatus fetchCurrentGap(SeqNoGap* gap);
+
+        // Causes the read pointer to skip over any portion of a gap indicated
+        // by nak.  If nak is NULL, any gap currently blocking the read pointer
+        // will be completely skipped.  If any portion of a gap is skipped, the
+        // next successful read from fetch buffer will indicate a discontinuity.
+        void processNAK(const SeqNoGap* nak = NULL);
+
+        // Compute the number of milliseconds until the inactivity timer for
+        // this RTP stream.  Returns -1 if there is no active timeout, or 0 if
+        // the system has already timed out.
+        int computeInactivityTimeout();
+
+      private:
+        Mutex          lock_;
+        PacketBuffer** ring_;
+        uint32_t       capacity_;
+        uint32_t       rd_;
+        uint32_t       wr_;
+
+        uint16_t       rd_seq_;
+        bool           rd_seq_known_;
+        bool           waiting_for_fast_start_;
+        bool           fetched_first_packet_;
+
+        uint64_t       rtp_activity_timeout_;
+        bool           rtp_activity_timeout_valid_;
+
+        DISALLOW_EVIL_CONSTRUCTORS(RXRingBuffer);
+    };
+
+    class Substream : public virtual RefBase {
+      public:
+        Substream(uint32_t ssrc, OMXClient& omx);
+
+        void cleanupBufferInProgress();
+        void shutdown();
+        void processPayloadStart(uint8_t* buf,
+                                 uint32_t amt,
+                                 int32_t ts_lower);
+        void processPayloadCont (uint8_t* buf,
+                                 uint32_t amt);
+        void processTSTransform(const LinearTransform& trans);
+
+        bool     isAboutToUnderflow();
+        uint32_t getSSRC()      const { return ssrc_; }
+        uint16_t getProgramID() const { return (ssrc_ >> 5) & 0x1F; }
+        status_t getStatus() const { return status_; }
+
+      protected:
+        virtual ~Substream() {
+            shutdown();
+        }
+
+      private:
+        void                cleanupDecoder();
+        bool                shouldAbort(const char* log_tag);
+        void                processCompletedBuffer();
+        bool                setupSubstreamType(uint8_t substream_type,
+                                               uint8_t codec_type);
+
+        uint32_t            ssrc_;
+        bool                waiting_for_rap_;
+        status_t            status_;
+
+        bool                substream_details_known_;
+        uint8_t             substream_type_;
+        uint8_t             codec_type_;
+        sp<MetaData>        substream_meta_;
+
+        MediaBuffer*        buffer_in_progress_;
+        uint32_t            expected_buffer_size_;
+        uint32_t            buffer_filled_;
+
+        sp<AAH_DecoderPump> decoder_;
+
+        static int64_t      kAboutToUnderflowThreshold;
+
+        DISALLOW_EVIL_CONSTRUCTORS(Substream);
+    };
+
+    typedef DefaultKeyedVector< uint32_t, sp<Substream> > SubstreamVec;
+
+    status_t            startWorkThread();
+    void                stopWorkThread();
+    virtual bool        threadLoop();
+    bool                setupSocket();
+    void                cleanupSocket();
+    void                resetPipeline();
+    void                reset_l();
+    bool                processRX(PacketBuffer* pb);
+    void                processRingBuffer();
+    void                processCommandPacket(PacketBuffer* pb);
+    bool                processGaps();
+    int                 computeNextGapRetransmitTimeout();
+    void                fetchAudioFlinger();
+
+    PipeEvent           wakeup_work_thread_evt_;
+    sp<ThreadWrapper>   thread_wrapper_;
+    Mutex               api_lock_;
+    bool                is_playing_;
+    bool                data_source_set_;
+
+    struct sockaddr_in  listen_addr_;
+    int                 sock_fd_;
+    bool                multicast_joined_;
+
+    struct sockaddr_in  transmitter_addr_;
+    bool                transmitter_known_;
+
+    uint32_t            current_epoch_;
+    bool                current_epoch_known_;
+
+    SeqNoGap            current_gap_;
+    GapStatus           current_gap_status_;
+    uint64_t            next_retrans_req_time_;
+
+    RXRingBuffer        ring_buffer_;
+    SubstreamVec        substreams_;
+    OMXClient           omx_;
+    CCHelper            cc_helper_;
+
+    // Connection to audio flinger used to hack a path to setMasterVolume.
+    sp<IAudioFlinger>   audio_flinger_;
+
+    static const uint32_t kRTPRingBufferSize;
+    static const uint32_t kRetransRequestMagic;
+    static const uint32_t kFastStartRequestMagic;
+    static const uint32_t kRetransNAKMagic;
+    static const uint32_t kGapRerequestTimeoutUSec;
+    static const uint32_t kFastStartTimeoutUSec;
+    static const uint32_t kRTPActivityTimeoutUSec;
+
+    static const uint32_t INVOKE_GET_MASTER_VOLUME = 3;
+    static const uint32_t INVOKE_SET_MASTER_VOLUME = 4;
+
+    static uint64_t monotonicUSecNow();
+
+    DISALLOW_EVIL_CONSTRUCTORS(AAH_RXPlayer);
+};
+
+}  // namespace android
+
+#endif  // __AAH_RX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_rx_player_core.cpp b/media/libaah_rtp/aah_rx_player_core.cpp
new file mode 100644
index 0000000..d2b3386
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player_core.cpp
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <utils/misc.h>
+
+#include <media/stagefright/Utils.h>
+
+#include "aah_rx_player.h"
+#include "aah_tx_packet.h"
+
+namespace android {
+
+const uint32_t AAH_RXPlayer::kRetransRequestMagic =
+    FOURCC('T','r','e','q');
+const uint32_t AAH_RXPlayer::kRetransNAKMagic =
+    FOURCC('T','n','a','k');
+const uint32_t AAH_RXPlayer::kFastStartRequestMagic =
+    FOURCC('T','f','s','t');
+const uint32_t AAH_RXPlayer::kGapRerequestTimeoutUSec = 75000;
+const uint32_t AAH_RXPlayer::kFastStartTimeoutUSec = 800000;
+const uint32_t AAH_RXPlayer::kRTPActivityTimeoutUSec = 10000000;
+
+static inline int16_t fetchInt16(uint8_t* data) {
+    return static_cast<int16_t>(U16_AT(data));
+}
+
+static inline int32_t fetchInt32(uint8_t* data) {
+    return static_cast<int32_t>(U32_AT(data));
+}
+
+static inline int64_t fetchInt64(uint8_t* data) {
+    return static_cast<int64_t>(U64_AT(data));
+}
+
+uint64_t AAH_RXPlayer::monotonicUSecNow() {
+    struct timespec now;
+    int res = clock_gettime(CLOCK_MONOTONIC, &now);
+    CHECK(res >= 0);
+
+    uint64_t ret = static_cast<uint64_t>(now.tv_sec) * 1000000;
+    ret += now.tv_nsec / 1000;
+
+    return ret;
+}
+
+status_t AAH_RXPlayer::startWorkThread() {
+    status_t res;
+    stopWorkThread();
+    res = thread_wrapper_->run("TRX_Player", PRIORITY_AUDIO);
+
+    if (res != OK) {
+        ALOGE("Failed to start work thread (res = %d)", res);
+    }
+
+    return res;
+}
+
+void AAH_RXPlayer::stopWorkThread() {
+    thread_wrapper_->requestExit();  // set the exit pending flag
+    wakeup_work_thread_evt_.setEvent();
+
+    status_t res;
+    res = thread_wrapper_->requestExitAndWait(); // block until thread exit.
+    if (res != OK) {
+        ALOGE("Failed to stop work thread (res = %d)", res);
+    }
+
+    wakeup_work_thread_evt_.clearPendingEvents();
+}
+
+void AAH_RXPlayer::cleanupSocket() {
+    if (sock_fd_ >= 0) {
+        if (multicast_joined_) {
+            int res;
+            struct ip_mreq mreq;
+            mreq.imr_multiaddr = listen_addr_.sin_addr;
+            mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+            res = setsockopt(sock_fd_,
+                             IPPROTO_IP,
+                             IP_DROP_MEMBERSHIP,
+                             &mreq, sizeof(mreq));
+            if (res < 0) {
+                ALOGW("Failed to leave multicast group. (%d, %d)", res, errno);
+            }
+            multicast_joined_ = false;
+        }
+
+        close(sock_fd_);
+        sock_fd_ = -1;
+    }
+
+    resetPipeline();
+}
+
+void AAH_RXPlayer::resetPipeline() {
+    ring_buffer_.reset();
+
+    // Explicitly shudown all of the active substreams, then call clear out the
+    // collection.  Failure to clear out a substream can result in its decoder
+    // holding a reference to itself and therefor not going away when the
+    // collection is cleared.
+    for (size_t i = 0; i < substreams_.size(); ++i)
+        substreams_.valueAt(i)->shutdown();
+
+    substreams_.clear();
+
+    current_gap_status_ = kGS_NoGap;
+}
+
+bool AAH_RXPlayer::setupSocket() {
+    long flags;
+    int  res, buf_size;
+    socklen_t opt_size;
+
+    cleanupSocket();
+    CHECK(sock_fd_ < 0);
+
+    // Make the socket
+    sock_fd_ = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (sock_fd_ < 0) {
+        ALOGE("Failed to create listen socket (errno %d)", errno);
+        goto bailout;
+    }
+
+    // Set non-blocking operation
+    flags = fcntl(sock_fd_, F_GETFL);
+    res   = fcntl(sock_fd_, F_SETFL, flags | O_NONBLOCK);
+    if (res < 0) {
+        ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
+              sock_fd_, errno);
+        goto bailout;
+    }
+
+    // Bind to our port
+    struct sockaddr_in bind_addr;
+    memset(&bind_addr, 0, sizeof(bind_addr));
+    bind_addr.sin_family = AF_INET;
+    bind_addr.sin_addr.s_addr = INADDR_ANY;
+    bind_addr.sin_port = listen_addr_.sin_port;
+    res = bind(sock_fd_,
+               reinterpret_cast<const sockaddr*>(&bind_addr),
+               sizeof(bind_addr));
+    if (res < 0) {
+        uint32_t a = ntohl(bind_addr.sin_addr.s_addr);
+        uint16_t p = ntohs(bind_addr.sin_port);
+        ALOGE("Failed to bind socket (%d) to %d.%d.%d.%d:%hd. (errno %d)",
+              sock_fd_,
+              (a >> 24) & 0xFF,
+              (a >> 16) & 0xFF,
+              (a >>  8) & 0xFF,
+              (a      ) & 0xFF,
+              p,
+              errno);
+
+        goto bailout;
+    }
+
+    buf_size = 1 << 16;   // 64k
+    res = setsockopt(sock_fd_,
+                     SOL_SOCKET, SO_RCVBUF,
+                     &buf_size, sizeof(buf_size));
+    if (res < 0) {
+        ALOGW("Failed to increase socket buffer size to %d.  (errno %d)",
+              buf_size, errno);
+    }
+
+    buf_size = 0;
+    opt_size = sizeof(buf_size);
+    res = getsockopt(sock_fd_,
+                     SOL_SOCKET, SO_RCVBUF,
+                     &buf_size, &opt_size);
+    if (res < 0) {
+        ALOGW("Failed to fetch socket buffer size.  (errno %d)", errno);
+    } else {
+        ALOGI("RX socket buffer size is now %d bytes",  buf_size);
+    }
+
+    if (listen_addr_.sin_addr.s_addr) {
+        // Join the multicast group and we should be good to go.
+        struct ip_mreq mreq;
+        mreq.imr_multiaddr = listen_addr_.sin_addr;
+        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+        res = setsockopt(sock_fd_,
+                         IPPROTO_IP,
+                         IP_ADD_MEMBERSHIP,
+                         &mreq, sizeof(mreq));
+        if (res < 0) {
+            ALOGE("Failed to join multicast group. (errno %d)", errno);
+            goto bailout;
+        }
+        multicast_joined_ = true;
+    }
+
+    return true;
+
+bailout:
+    cleanupSocket();
+    return false;
+}
+
+bool AAH_RXPlayer::threadLoop() {
+    struct pollfd poll_fds[2];
+    bool process_more_right_now = false;
+
+    if (!setupSocket()) {
+        sendEvent(MEDIA_ERROR);
+        goto bailout;
+    }
+
+    while (!thread_wrapper_->exitPending()) {
+        // Step 1: Wait until there is something to do.
+        int gap_timeout = computeNextGapRetransmitTimeout();
+        int ring_timeout = ring_buffer_.computeInactivityTimeout();
+        int timeout = -1;
+
+        if (!ring_timeout) {
+            ALOGW("RTP inactivity timeout reached, resetting pipeline.");
+            resetPipeline();
+            timeout = gap_timeout;
+        } else {
+            if (gap_timeout < 0) {
+                timeout = ring_timeout;
+            } else if (ring_timeout < 0) {
+                timeout = gap_timeout;
+            } else {
+                timeout = (gap_timeout < ring_timeout) ? gap_timeout
+                                                       : ring_timeout;
+            }
+        }
+
+        if ((0 != timeout) && (!process_more_right_now)) {
+            // Set up the events to wait on.  Start with the wakeup pipe.
+            memset(&poll_fds, 0, sizeof(poll_fds));
+            poll_fds[0].fd     = wakeup_work_thread_evt_.getWakeupHandle();
+            poll_fds[0].events = POLLIN;
+
+            // Add the RX socket.
+            poll_fds[1].fd     = sock_fd_;
+            poll_fds[1].events = POLLIN;
+
+            // Wait for something interesing to happen.
+            int poll_res = poll(poll_fds, NELEM(poll_fds), timeout);
+            if (poll_res < 0) {
+                ALOGE("Fatal error (%d,%d) while waiting on events",
+                      poll_res, errno);
+                sendEvent(MEDIA_ERROR);
+                goto bailout;
+            }
+        }
+
+        if (thread_wrapper_->exitPending()) {
+            break;
+        }
+
+        wakeup_work_thread_evt_.clearPendingEvents();
+        process_more_right_now = false;
+
+        // Step 2: Do we have data waiting in the socket?  If so, drain the
+        // socket moving valid RTP information into the ring buffer to be
+        // processed.
+        if (poll_fds[1].revents) {
+            struct sockaddr_in from;
+            socklen_t from_len;
+
+            ssize_t res = 0;
+            while (!thread_wrapper_->exitPending()) {
+                // Check the size of any pending packet.
+                res = recv(sock_fd_, NULL, 0, MSG_PEEK | MSG_TRUNC);
+
+                // Error?
+                if (res < 0) {
+                    // If the error is anything other than would block,
+                    // something has gone very wrong.
+                    if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) {
+                        ALOGE("Fatal socket error during recvfrom (%d, %d)",
+                              (int)res, errno);
+                        goto bailout;
+                    }
+
+                    // Socket is out of data, just break out of processing and
+                    // wait for more.
+                    break;
+                }
+
+                // Allocate a payload.
+                PacketBuffer* pb = PacketBuffer::allocate(res);
+                if (NULL == pb) {
+                    ALOGE("Fatal error, failed to allocate packet buffer of"
+                          " length %u", static_cast<uint32_t>(res));
+                    goto bailout;
+                }
+
+                // Fetch the data.
+                from_len = sizeof(from);
+                res = recvfrom(sock_fd_, pb->data_, pb->length_, 0,
+                               reinterpret_cast<struct sockaddr*>(&from),
+                               &from_len);
+                if (res != pb->length_) {
+                    ALOGE("Fatal error, fetched packet length (%d) does not"
+                          " match peeked packet length (%u).  This should never"
+                          " happen.  (errno = %d)",
+                          static_cast<int>(res),
+                          static_cast<uint32_t>(pb->length_),
+                          errno);
+                }
+
+                bool drop_packet = false;
+                if (transmitter_known_) {
+                    if (from.sin_addr.s_addr !=
+                        transmitter_addr_.sin_addr.s_addr) {
+                        uint32_t a = ntohl(from.sin_addr.s_addr);
+                        uint16_t p = ntohs(from.sin_port);
+                        ALOGV("Dropping packet from unknown transmitter"
+                              " %u.%u.%u.%u:%hu",
+                              ((a >> 24) & 0xFF),
+                              ((a >> 16) & 0xFF),
+                              ((a >>  8) & 0xFF),
+                              ( a        & 0xFF),
+                              p);
+
+                        drop_packet = true;
+                    } else {
+                        transmitter_addr_.sin_port = from.sin_port;
+                    }
+                } else {
+                    memcpy(&transmitter_addr_, &from, sizeof(from));
+                    transmitter_known_ = true;
+                }
+
+                if (!drop_packet) {
+                    bool serious_error = !processRX(pb);
+
+                    if (serious_error) {
+                        // Something went "seriously wrong".  Currently, the
+                        // only trigger for this should be a ring buffer
+                        // overflow.  The current failsafe behavior for when
+                        // something goes seriously wrong is to just reset the
+                        // pipeline.  The system should behave as if this
+                        // AAH_RXPlayer was just set up for the first time.
+                        ALOGE("Something just went seriously wrong with the"
+                              " pipeline.  Resetting.");
+                        resetPipeline();
+                    }
+                } else {
+                    PacketBuffer::destroy(pb);
+                }
+            }
+        }
+
+        // Step 3: Process any data we mave have accumulated in the ring buffer
+        // so far.
+        if (!thread_wrapper_->exitPending()) {
+            processRingBuffer();
+        }
+
+        // Step 4: At this point in time, the ring buffer should either be
+        // empty, or stalled in front of a gap caused by some dropped packets.
+        // Check on the current gap situation and deal with it in an appropriate
+        // fashion.  If processGaps returns true, it means that it has given up
+        // on a gap and that we should try to process some more data
+        // immediately.
+        if (!thread_wrapper_->exitPending()) {
+            process_more_right_now = processGaps();
+        }
+
+        // Step 5: Check for fatal errors.  If any of our substreams has
+        // encountered a fatal, unrecoverable, error, then propagate the error
+        // up to user level and shut down.
+        for (size_t i = 0; i < substreams_.size(); ++i) {
+            status_t status;
+            CHECK(substreams_.valueAt(i) != NULL);
+
+            status = substreams_.valueAt(i)->getStatus();
+            if (OK != status) {
+                ALOGE("Substream index %d has encountered an unrecoverable"
+                      " error (%d).  Signalling application level and shutting"
+                      " down.", i, status);
+                sendEvent(MEDIA_ERROR);
+                goto bailout;
+            }
+        }
+    }
+
+bailout:
+    cleanupSocket();
+    return false;
+}
+
+bool AAH_RXPlayer::processRX(PacketBuffer* pb) {
+    CHECK(NULL != pb);
+
+    uint8_t* data = pb->data_;
+    ssize_t  amt  = pb->length_;
+    uint32_t nak_magic;
+    uint16_t seq_no;
+    uint32_t epoch;
+
+    // Every packet either starts with an RTP header which is at least 12 bytes
+    // long or is a retry NAK which is 14 bytes long.  If there are fewer than
+    // 12 bytes here, this cannot be a proper RTP packet.
+    if (amt < 12) {
+        ALOGV("Dropping packet, too short to contain RTP header (%u bytes)",
+              static_cast<uint32_t>(amt));
+        goto drop_packet;
+    }
+
+    // Check to see if this is the special case of a NAK packet.
+    nak_magic = ntohl(*(reinterpret_cast<uint32_t*>(data)));
+    if (nak_magic == kRetransNAKMagic) {
+        // Looks like a NAK packet; make sure its long enough.
+
+        if (amt < static_cast<ssize_t>(sizeof(RetransRequest))) {
+            ALOGV("Dropping packet, too short to contain NAK payload (%u bytes)",
+                  static_cast<uint32_t>(amt));
+            goto drop_packet;
+        }
+
+        SeqNoGap gap;
+        RetransRequest* rtr = reinterpret_cast<RetransRequest*>(data);
+        gap.start_seq_ = ntohs(rtr->start_seq_);
+        gap.end_seq_   = ntohs(rtr->end_seq_);
+
+        ALOGV("Process NAK for gap at [%hu, %hu]", gap.start_seq_, gap.end_seq_);
+        ring_buffer_.processNAK(&gap);
+
+        return true;
+    }
+
+    // According to the TRTP spec, version should be 2, padding should be 0,
+    // extension should be 0 and CSRCCnt should be 0.  If any of these tests
+    // fail, we chuck the packet.
+    if (data[0] != 0x80) {
+        ALOGV("Dropping packet, bad V/P/X/CSRCCnt field (0x%02x)",
+              data[0]);
+        goto drop_packet;
+    }
+
+    // Check the payload type.  For TRTP, it should always be 100.
+    if ((data[1] & 0x7F) != 100) {
+        ALOGV("Dropping packet, bad payload type. (%u)",
+              data[1] & 0x7F);
+        goto drop_packet;
+    }
+
+    // Check whether the transmitter has begun a new epoch.
+    epoch = (U32_AT(data + 8) >> 10) & 0x3FFFFF;
+    if (current_epoch_known_) {
+        if (epoch != current_epoch_) {
+            ALOGV("%s: new epoch %u", __PRETTY_FUNCTION__, epoch);
+            current_epoch_ = epoch;
+            resetPipeline();
+        }
+    } else {
+        current_epoch_ = epoch;
+        current_epoch_known_ = true;
+    }
+
+    // Extract the sequence number and hand the packet off to the ring buffer
+    // for dropped packet detection and later processing.
+    seq_no = U16_AT(data + 2);
+    return ring_buffer_.pushBuffer(pb, seq_no);
+
+drop_packet:
+    PacketBuffer::destroy(pb);
+    return true;
+}
+
+void AAH_RXPlayer::processRingBuffer() {
+    PacketBuffer* pb;
+    bool is_discon;
+    sp<Substream> substream;
+    LinearTransform trans;
+    bool foundTrans = false;
+
+    while (NULL != (pb = ring_buffer_.fetchBuffer(&is_discon))) {
+        if (is_discon) {
+            // Abort all partially assembled payloads.
+            for (size_t i = 0; i < substreams_.size(); ++i) {
+                CHECK(substreams_.valueAt(i) != NULL);
+                substreams_.valueAt(i)->cleanupBufferInProgress();
+            }
+        }
+
+        uint8_t* data = pb->data_;
+        ssize_t  amt  = pb->length_;
+
+        // Should not have any non-RTP packets in the ring buffer.  RTP packets
+        // must be at least 12 bytes long.
+        CHECK(amt >= 12);
+
+        // Extract the marker bit and the SSRC field.
+        bool     marker = (data[1] & 0x80) != 0;
+        uint32_t ssrc   = U32_AT(data + 8);
+
+        // Is this the start of a new TRTP payload?  If so, the marker bit
+        // should be set and there are some things we should be checking for.
+        if (marker) {
+            // TRTP headers need to have at least a byte for version, a byte for
+            // payload type and flags, and 4 bytes for length.
+            if (amt < 18) {
+                ALOGV("Dropping packet, too short to contain TRTP header"
+                      " (%u bytes)", static_cast<uint32_t>(amt));
+                goto process_next_packet;
+            }
+
+            // Check the TRTP version and extract the payload type/flags.
+            uint8_t trtp_version =  data[12];
+            uint8_t payload_type = (data[13] >> 4) & 0xF;
+            uint8_t trtp_flags   =  data[13]       & 0xF;
+
+            if (1 != trtp_version) {
+                ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
+                goto process_next_packet;
+            }
+
+            // Is there a timestamp transformation present on this packet?  If
+            // so, extract it and pass it to the appropriate substreams.
+            if (trtp_flags & 0x02) {
+                ssize_t offset = 18 + ((trtp_flags & 0x01) ? 4 : 0);
+                if (amt < (offset + 24)) {
+                    ALOGV("Dropping packet, too short to contain TRTP Timestamp"
+                          " Transformation (%u bytes)",
+                          static_cast<uint32_t>(amt));
+                    goto process_next_packet;
+                }
+
+                trans.a_zero = fetchInt64(data + offset);
+                trans.b_zero = fetchInt64(data + offset + 16);
+                trans.a_to_b_numer = static_cast<int32_t>(
+                        fetchInt32 (data + offset + 8));
+                trans.a_to_b_denom = U32_AT(data + offset + 12);
+                foundTrans = true;
+
+                uint32_t program_id = (ssrc >> 5) & 0x1F;
+                for (size_t i = 0; i < substreams_.size(); ++i) {
+                    sp<Substream> iter = substreams_.valueAt(i);
+                    CHECK(iter != NULL);
+
+                    if (iter->getProgramID() == program_id) {
+                        iter->processTSTransform(trans);
+                    }
+                }
+            }
+
+            // Is this a command packet?  If so, its not necessarily associate
+            // with one particular substream.  Just give it to the command
+            // packet handler and then move on.
+            if (4 == payload_type) {
+                processCommandPacket(pb);
+                goto process_next_packet;
+            }
+        }
+
+        // If we got to here, then we are a normal packet.  Find (or allocate)
+        // the substream we belong to and send the packet off to be processed.
+        substream = substreams_.valueFor(ssrc);
+        if (substream == NULL) {
+            substream = new Substream(ssrc, omx_);
+            if (substream == NULL) {
+                ALOGE("Failed to allocate substream for SSRC 0x%08x", ssrc);
+                goto process_next_packet;
+            }
+            substreams_.add(ssrc, substream);
+
+            if (foundTrans) {
+                substream->processTSTransform(trans);
+            }
+        }
+
+        CHECK(substream != NULL);
+
+        if (marker) {
+            // Start of a new TRTP payload for this substream.  Extract the
+            // lower 32 bits of the timestamp and hand the buffer to the
+            // substream for processing.
+            uint32_t ts_lower = U32_AT(data + 4);
+            substream->processPayloadStart(data + 12, amt - 12, ts_lower);
+        } else {
+            // Continuation of an existing TRTP payload.  Just hand it off to
+            // the substream for processing.
+            substream->processPayloadCont(data + 12, amt - 12);
+        }
+
+process_next_packet:
+        PacketBuffer::destroy(pb);
+    }  // end of main processing while loop.
+}
+
+void AAH_RXPlayer::processCommandPacket(PacketBuffer* pb) {
+    CHECK(NULL != pb);
+
+    uint8_t* data = pb->data_;
+    ssize_t  amt  = pb->length_;
+
+    // verify that this packet meets the minimum length of a command packet
+    if (amt < 20) {
+        return;
+    }
+
+    uint8_t trtp_version =  data[12];
+    uint8_t trtp_flags   =  data[13]       & 0xF;
+
+    if (1 != trtp_version) {
+        ALOGV("Dropping packet, bad trtp version %hhu", trtp_version);
+        return;
+    }
+
+    // calculate the start of the command payload
+    ssize_t offset = 18;
+    if (trtp_flags & 0x01) {
+        // timestamp is present (4 bytes)
+        offset += 4;
+    }
+    if (trtp_flags & 0x02) {
+        // transform is present (24 bytes)
+        offset += 24;
+    }
+
+    // the packet must contain 2 bytes of command payload beyond the TRTP header
+    if (amt < offset + 2) {
+        return;
+    }
+
+    uint16_t command_id = U16_AT(data + offset);
+
+    switch (command_id) {
+        case TRTPControlPacket::kCommandNop:
+            break;
+
+        case TRTPControlPacket::kCommandEOS:
+        case TRTPControlPacket::kCommandFlush: {
+            uint16_t program_id = (U32_AT(data + 8) >> 5) & 0x1F;
+            ALOGI("*** %s flushing program_id=%d",
+                  __PRETTY_FUNCTION__, program_id);
+
+            Vector<uint32_t> substreams_to_remove;
+            for (size_t i = 0; i < substreams_.size(); ++i) {
+                sp<Substream> iter = substreams_.valueAt(i);
+                if (iter->getProgramID() == program_id) {
+                    iter->shutdown();
+                    substreams_to_remove.add(iter->getSSRC());
+                }
+            }
+
+            for (size_t i = 0; i < substreams_to_remove.size(); ++i) {
+                substreams_.removeItem(substreams_to_remove[i]);
+            }
+        } break;
+    }
+}
+
+bool AAH_RXPlayer::processGaps() {
+    // Deal with the current gap situation.  Specifically...
+    //
+    // 1) If a new gap has shown up, send a retransmit request to the
+    //    transmitter.
+    // 2) If a gap we were working on has had a packet in the middle or at
+    //    the end filled in, send another retransmit request for the begining
+    //    portion of the gap.  TRTP was designed for LANs where packet
+    //    re-ordering is very unlikely; so see the middle or end of a gap
+    //    filled in before the begining is an almost certain indication that
+    //    a retransmission packet was also dropped.
+    // 3) If we have been working on a gap for a while and it still has not
+    //    been filled in, send another retransmit request.
+    // 4) If the are no more gaps in the ring, clear the current_gap_status_
+    //    flag to indicate that all is well again.
+
+    // Start by fetching the active gap status.
+    SeqNoGap gap;
+    bool send_retransmit_request = false;
+    bool ret_val = false;
+    GapStatus gap_status;
+    if (kGS_NoGap != (gap_status = ring_buffer_.fetchCurrentGap(&gap))) {
+        // Note: checking for a change in the end sequence number should cover
+        // moving on to an entirely new gap for case #1 as well as resending the
+        // begining of a gap range for case #2.
+        send_retransmit_request = (kGS_NoGap == current_gap_status_) ||
+                                  (current_gap_.end_seq_ != gap.end_seq_);
+
+        // If this is the same gap we have been working on, and it has timed
+        // out, then check to see if our substreams are about to underflow.  If
+        // so, instead of sending another retransmit request, just give up on
+        // this gap and move on.
+        if (!send_retransmit_request &&
+           (kGS_NoGap != current_gap_status_) &&
+           (0 == computeNextGapRetransmitTimeout())) {
+
+            // If out current gap is the fast-start gap, don't bother to skip it
+            // because substreams look like the are about to underflow.
+            if ((kGS_FastStartGap != gap_status) ||
+                (current_gap_.end_seq_ != gap.end_seq_)) {
+                for (size_t i = 0; i < substreams_.size(); ++i) {
+                    if (substreams_.valueAt(i)->isAboutToUnderflow()) {
+                        ALOGV("About to underflow, giving up on gap [%hu, %hu]",
+                              gap.start_seq_, gap.end_seq_);
+                        ring_buffer_.processNAK();
+                        current_gap_status_ = kGS_NoGap;
+                        return true;
+                    }
+                }
+            }
+
+            // Looks like no one is about to underflow.  Just go ahead and send
+            // the request.
+            send_retransmit_request = true;
+        }
+    } else {
+        current_gap_status_ = kGS_NoGap;
+    }
+
+    if (send_retransmit_request) {
+        // If we have been working on a fast start, and it is still not filled
+        // in, even after the extended retransmit time out, give up and skip it.
+        // The system should fall back into its normal slow-start behavior.
+        if ((kGS_FastStartGap == current_gap_status_) &&
+            (current_gap_.end_seq_ == gap.end_seq_)) {
+            ALOGV("Fast start is taking forever; giving up.");
+            ring_buffer_.processNAK();
+            current_gap_status_ = kGS_NoGap;
+            return true;
+        }
+
+        // Send the request.
+        RetransRequest req;
+        uint32_t magic  = (kGS_FastStartGap == gap_status)
+                        ? kFastStartRequestMagic
+                        : kRetransRequestMagic;
+        req.magic_      = htonl(magic);
+        req.mcast_ip_   = listen_addr_.sin_addr.s_addr;
+        req.mcast_port_ = listen_addr_.sin_port;
+        req.start_seq_  = htons(gap.start_seq_);
+        req.end_seq_    = htons(gap.end_seq_);
+
+        {
+            uint32_t a = ntohl(transmitter_addr_.sin_addr.s_addr);
+            uint16_t p = ntohs(transmitter_addr_.sin_port);
+            ALOGV("Sending to transmitter %u.%u.%u.%u:%hu",
+                    ((a >> 24) & 0xFF),
+                    ((a >> 16) & 0xFF),
+                    ((a >>  8) & 0xFF),
+                    ( a        & 0xFF),
+                    p);
+        }
+
+        int res = sendto(sock_fd_, &req, sizeof(req), 0,
+                         reinterpret_cast<struct sockaddr*>(&transmitter_addr_),
+                         sizeof(transmitter_addr_));
+        if (res < 0) {
+            ALOGE("Error when sending retransmit request (%d)", errno);
+        } else {
+            ALOGV("%s request for range [%hu, %hu] sent",
+                  (kGS_FastStartGap == gap_status) ? "Fast Start" : "Retransmit",
+                  gap.start_seq_, gap.end_seq_);
+        }
+
+        // Update the current gap info.
+        current_gap_ = gap;
+        current_gap_status_ = gap_status;
+        next_retrans_req_time_ = monotonicUSecNow() +
+                               ((kGS_FastStartGap == current_gap_status_)
+                                ? kFastStartTimeoutUSec
+                                : kGapRerequestTimeoutUSec);
+    }
+
+    return false;
+}
+
+// Compute when its time to send the next gap retransmission in milliseconds.
+// Returns < 0 for an infinite timeout (no gap) and 0 if its time to retransmit
+// right now.
+int AAH_RXPlayer::computeNextGapRetransmitTimeout() {
+    if (kGS_NoGap == current_gap_status_) {
+        return -1;
+    }
+
+    int64_t timeout_delta = next_retrans_req_time_ - monotonicUSecNow();
+
+    timeout_delta /= 1000;
+    if (timeout_delta <= 0) {
+        return 0;
+    }
+
+    return static_cast<uint32_t>(timeout_delta);
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_ring_buffer.cpp b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
new file mode 100644
index 0000000..0d8b31f
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player_ring_buffer.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include "aah_rx_player.h"
+
+namespace android {
+
+AAH_RXPlayer::RXRingBuffer::RXRingBuffer(uint32_t capacity) {
+    capacity_ = capacity;
+    rd_ = wr_ = 0;
+    ring_ = new PacketBuffer*[capacity];
+    memset(ring_, 0, sizeof(PacketBuffer*) * capacity);
+    reset();
+}
+
+AAH_RXPlayer::RXRingBuffer::~RXRingBuffer() {
+    reset();
+    delete[] ring_;
+}
+
+void AAH_RXPlayer::RXRingBuffer::reset() {
+    AutoMutex lock(&lock_);
+
+    if (NULL != ring_) {
+        while (rd_ != wr_) {
+            CHECK(rd_ < capacity_);
+            if (NULL != ring_[rd_]) {
+                PacketBuffer::destroy(ring_[rd_]);
+                ring_[rd_] = NULL;
+            }
+            rd_ = (rd_ + 1) % capacity_;
+        }
+    }
+
+    rd_ = wr_ = 0;
+    rd_seq_known_ = false;
+    waiting_for_fast_start_ = true;
+    fetched_first_packet_ = false;
+    rtp_activity_timeout_valid_ = false;
+}
+
+bool AAH_RXPlayer::RXRingBuffer::pushBuffer(PacketBuffer* buf,
+                                                uint16_t seq) {
+    AutoMutex lock(&lock_);
+    CHECK(NULL != ring_);
+    CHECK(NULL != buf);
+
+    rtp_activity_timeout_valid_ = true;
+    rtp_activity_timeout_ = monotonicUSecNow() + kRTPActivityTimeoutUSec;
+
+    // If the ring buffer is totally reset (we have never received a single
+    // payload) then we don't know the rd sequence number and this should be
+    // simple.  We just store the payload, advance the wr pointer and record the
+    // initial sequence number.
+    if (!rd_seq_known_) {
+        CHECK(rd_ == wr_);
+        CHECK(NULL == ring_[wr_]);
+        CHECK(wr_ < capacity_);
+
+        ring_[wr_] = buf;
+        wr_ = (wr_ + 1) % capacity_;
+        rd_seq_ = seq;
+        rd_seq_known_ = true;
+        return true;
+    }
+
+    // Compute the seqence number of this payload and of the write pointer,
+    // normalized around the read pointer.  IOW - transform the payload seq no
+    // and the wr pointer seq no into a space where the rd pointer seq no is
+    // zero.  This will define 4 cases we can consider...
+    //
+    // 1) norm_seq == norm_wr_seq
+    //    This payload is contiguous with the last.  All is good.
+    //
+    // 2)  ((norm_seq <  norm_wr_seq) && (norm_seq >= norm_rd_seq)
+    // aka ((norm_seq <  norm_wr_seq) && (norm_seq >= 0)
+    //    This payload is in the past, in the unprocessed region of the ring
+    //    buffer.  It is probably a retransmit intended to fill in a dropped
+    //    payload; it may be a duplicate.
+    //
+    // 3) ((norm_seq - norm_wr_seq) & 0x8000) != 0
+    //    This payload is in the past compared to the write pointer (or so very
+    //    far in the future that it has wrapped the seq no space), but not in
+    //    the unprocessed region of the ring buffer.  This could be a duplicate
+    //    retransmit; we just drop these payloads unless we are waiting for our
+    //    first fast start packet.  If we are waiting for fast start, than this
+    //    packet is probably the first packet of the fast start retransmission.
+    //    If it will fit in the buffer, back up the read pointer to its position
+    //    and clear the fast start flag, otherwise just drop it.
+    //
+    // 4) ((norm_seq - norm_wr_seq) & 0x8000) == 0
+    //    This payload which is ahead of the next write pointer.  This indicates
+    //    that we have missed some payloads and need to request a retransmit.
+    //    If norm_seq >= (capacity - 1), then the gap is so large that it would
+    //    overflow the ring buffer and we should probably start to panic.
+
+    uint16_t norm_wr_seq = ((wr_ + capacity_ - rd_) % capacity_);
+    uint16_t norm_seq    = seq - rd_seq_;
+
+    // Check for overflow first.
+    if ((!(norm_seq & 0x8000)) && (norm_seq >= (capacity_ - 1))) {
+        ALOGW("Ring buffer overflow; cap = %u, [rd, wr] = [%hu, %hu], seq = %hu",
+              capacity_, rd_seq_, norm_wr_seq + rd_seq_, seq);
+        PacketBuffer::destroy(buf);
+        return false;
+    }
+
+    // Check for case #1
+    if (norm_seq == norm_wr_seq) {
+        CHECK(wr_ < capacity_);
+        CHECK(NULL == ring_[wr_]);
+
+        ring_[wr_] = buf;
+        wr_ = (wr_ + 1) % capacity_;
+
+        CHECK(wr_ != rd_);
+        return true;
+    }
+
+    // Check case #2
+    uint32_t ring_pos = (rd_ + norm_seq) % capacity_;
+    if ((norm_seq < norm_wr_seq) && (!(norm_seq & 0x8000))) {
+        // Do we already have a payload for this slot?  If so, then this looks
+        // like a duplicate retransmit.  Just ignore it.
+        if (NULL != ring_[ring_pos]) {
+            ALOGD("RXed duplicate retransmit, seq = %hu", seq);
+            PacketBuffer::destroy(buf);
+        } else {
+            // Looks like we were missing this payload.  Go ahead and store it.
+            ring_[ring_pos] = buf;
+        }
+
+        return true;
+    }
+
+    // Check case #3
+    if ((norm_seq - norm_wr_seq) & 0x8000) {
+        if (!waiting_for_fast_start_) {
+            ALOGD("RXed duplicate retransmit from before rd pointer, seq = %hu",
+                  seq);
+            PacketBuffer::destroy(buf);
+        } else {
+            // Looks like a fast start fill-in.  Go ahead and store it, assuming
+            // that we can fit it in the buffer.
+            uint32_t implied_ring_size = static_cast<uint32_t>(norm_wr_seq)
+                                       + (rd_seq_ - seq);
+
+            if (implied_ring_size >= (capacity_ - 1)) {
+                ALOGD("RXed what looks like a fast start packet (seq = %hu),"
+                      " but packet is too far in the past to fit into the ring"
+                      "  buffer.  Dropping.", seq);
+                PacketBuffer::destroy(buf);
+            } else {
+                ring_pos = (rd_ + capacity_ + seq - rd_seq_) % capacity_;
+                rd_seq_ = seq;
+                rd_ = ring_pos;
+                waiting_for_fast_start_ = false;
+
+                CHECK(ring_pos < capacity_);
+                CHECK(NULL == ring_[ring_pos]);
+                ring_[ring_pos] = buf;
+            }
+
+        }
+        return true;
+    }
+
+    // Must be in case #4 with no overflow.  This packet fits in the current
+    // ring buffer, but is discontiuguous.  Advance the write pointer leaving a
+    // gap behind.
+    uint32_t gap_len = (ring_pos + capacity_ - wr_) % capacity_;
+    ALOGD("Drop detected; %u packets, seq_range [%hu, %hu]",
+          gap_len,
+          rd_seq_ + norm_wr_seq,
+          rd_seq_ + norm_wr_seq + gap_len - 1);
+
+    CHECK(NULL == ring_[ring_pos]);
+    ring_[ring_pos] = buf;
+    wr_ = (ring_pos + 1) % capacity_;
+    CHECK(wr_ != rd_);
+
+    return true;
+}
+
+AAH_RXPlayer::PacketBuffer*
+AAH_RXPlayer::RXRingBuffer::fetchBuffer(bool* is_discon) {
+    AutoMutex lock(&lock_);
+    CHECK(NULL != ring_);
+    CHECK(NULL != is_discon);
+
+    // If the read seqence number is not known, then this ring buffer has not
+    // received a packet since being reset and there cannot be any packets to
+    // return.  If we are still waiting for the first fast start packet to show
+    // up, we don't want to let any buffer be consumed yet because we expect to
+    // see a packet before the initial read sequence number show up shortly.
+    if (!rd_seq_known_ || waiting_for_fast_start_) {
+        *is_discon = false;
+        return NULL;
+    }
+
+    PacketBuffer* ret = NULL;
+    *is_discon = !fetched_first_packet_;
+
+    while ((rd_ != wr_) && (NULL == ret)) {
+        CHECK(rd_ < capacity_);
+
+        // If we hit a gap, stall and do not advance the read pointer.  Let the
+        // higher level code deal with requesting retries and/or deciding to
+        // skip the current gap.
+        ret = ring_[rd_];
+        if (NULL == ret) {
+            break;
+        }
+
+        ring_[rd_] = NULL;
+        rd_ = (rd_ + 1) % capacity_;
+        ++rd_seq_;
+    }
+
+    if (NULL != ret) {
+        fetched_first_packet_ = true;
+    }
+
+    return ret;
+}
+
+AAH_RXPlayer::GapStatus
+AAH_RXPlayer::RXRingBuffer::fetchCurrentGap(SeqNoGap* gap) {
+    AutoMutex lock(&lock_);
+    CHECK(NULL != ring_);
+    CHECK(NULL != gap);
+
+    // If the read seqence number is not known, then this ring buffer has not
+    // received a packet since being reset and there cannot be any gaps.
+    if (!rd_seq_known_) {
+        return kGS_NoGap;
+    }
+
+    // If we are waiting for fast start, then the current gap is a fast start
+    // gap and it includes all packets before the read sequence number.
+    if (waiting_for_fast_start_) {
+        gap->start_seq_ =
+        gap->end_seq_   = rd_seq_ - 1;
+        return kGS_FastStartGap;
+    }
+
+    // If rd == wr, then the buffer is empty and there cannot be any gaps.
+    if (rd_ == wr_) {
+        return kGS_NoGap;
+    }
+
+    // If rd_ is currently pointing at an unprocessed packet, then there is no
+    // current gap.
+    CHECK(rd_ < capacity_);
+    if (NULL != ring_[rd_]) {
+        return kGS_NoGap;
+    }
+
+    // Looks like there must be a gap here.  The start of the gap is the current
+    // rd sequence number, all we need to do now is determine its length in
+    // order to compute the end sequence number.
+    gap->start_seq_ = rd_seq_;
+    uint16_t end = rd_seq_;
+    uint32_t tmp = (rd_ + 1) % capacity_;
+    while ((tmp != wr_) && (NULL == ring_[tmp])) {
+        ++end;
+        tmp = (tmp + 1) % capacity_;
+    }
+    gap->end_seq_ = end;
+
+    return kGS_NormalGap;
+}
+
+void AAH_RXPlayer::RXRingBuffer::processNAK(const SeqNoGap* nak) {
+    AutoMutex lock(&lock_);
+    CHECK(NULL != ring_);
+
+    // If we were waiting for our first fast start fill-in packet, and we
+    // received a NAK, then apparantly we are not getting our fast start.  Just
+    // clear the waiting flag and go back to normal behavior.
+    if (waiting_for_fast_start_) {
+        waiting_for_fast_start_ = false;
+    }
+
+    // If we have not received a packet since last reset, or there is no data in
+    // the ring, then there is nothing to skip.
+    if ((!rd_seq_known_) || (rd_ == wr_)) {
+        return;
+    }
+
+    // If rd_ is currently pointing at an unprocessed packet, then there is no
+    // gap to skip.
+    CHECK(rd_ < capacity_);
+    if (NULL != ring_[rd_]) {
+        return;
+    }
+
+    // Looks like there must be a gap here.  Advance rd until we have passed
+    // over the portion of it indicated by nak (or all of the gap if nak is
+    // NULL).  Then reset fetched_first_packet_ so that the next read will show
+    // up as being discontiguous.
+    uint16_t seq_after_gap = (NULL == nak) ? 0 : nak->end_seq_ + 1;
+    while ((rd_ != wr_) &&
+           (NULL == ring_[rd_]) &&
+          ((NULL == nak) || (seq_after_gap != rd_seq_))) {
+        rd_ = (rd_ + 1) % capacity_;
+        ++rd_seq_;
+    }
+    fetched_first_packet_ = false;
+}
+
+int AAH_RXPlayer::RXRingBuffer::computeInactivityTimeout() {
+    AutoMutex lock(&lock_);
+
+    if (!rtp_activity_timeout_valid_) {
+        return -1;
+    }
+
+    uint64_t now = monotonicUSecNow();
+    if (rtp_activity_timeout_ <= now) {
+        return 0;
+    }
+
+    return (rtp_activity_timeout_ - now) / 1000;
+}
+
+AAH_RXPlayer::PacketBuffer*
+AAH_RXPlayer::PacketBuffer::allocate(ssize_t length) {
+    if (length <= 0) {
+        return NULL;
+    }
+
+    uint32_t alloc_len = sizeof(PacketBuffer) + length;
+    PacketBuffer* ret = reinterpret_cast<PacketBuffer*>(
+                        new uint8_t[alloc_len]);
+
+    if (NULL != ret) {
+        ret->length_ = length;
+    }
+
+    return ret;
+}
+
+void AAH_RXPlayer::PacketBuffer::destroy(PacketBuffer* pb) {
+    uint8_t* kill_me = reinterpret_cast<uint8_t*>(pb);
+    delete[] kill_me;
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_rx_player_substream.cpp b/media/libaah_rtp/aah_rx_player_substream.cpp
new file mode 100644
index 0000000..1e4c784
--- /dev/null
+++ b/media/libaah_rtp/aah_rx_player_substream.cpp
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include <include/avc_utils.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
+#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/Utils.h>
+
+#include "aah_rx_player.h"
+
+namespace android {
+
+int64_t AAH_RXPlayer::Substream::kAboutToUnderflowThreshold =
+    50ull * 1000;
+
+AAH_RXPlayer::Substream::Substream(uint32_t ssrc, OMXClient& omx) {
+    ssrc_ = ssrc;
+    substream_details_known_ = false;
+    buffer_in_progress_ = NULL;
+    status_ = OK;
+
+    decoder_ = new AAH_DecoderPump(omx);
+    if (decoder_ == NULL) {
+        ALOGE("%s failed to allocate decoder pump!", __PRETTY_FUNCTION__);
+    }
+    if (OK != decoder_->initCheck()) {
+        ALOGE("%s failed to initialize decoder pump!", __PRETTY_FUNCTION__);
+    }
+
+    // cleanupBufferInProgress will reset most of the internal state variables.
+    // Just need to make sure that buffer_in_progress_ is NULL before calling.
+    cleanupBufferInProgress();
+}
+
+
+void AAH_RXPlayer::Substream::shutdown() {
+    substream_meta_ = NULL;
+    status_ = OK;
+    cleanupBufferInProgress();
+    cleanupDecoder();
+}
+
+void AAH_RXPlayer::Substream::cleanupBufferInProgress() {
+    if (NULL != buffer_in_progress_) {
+        buffer_in_progress_->release();
+        buffer_in_progress_ = NULL;
+    }
+
+    expected_buffer_size_ = 0;
+    buffer_filled_ = 0;
+    waiting_for_rap_ = true;
+}
+
+void AAH_RXPlayer::Substream::cleanupDecoder() {
+    if (decoder_ != NULL) {
+        decoder_->shutdown();
+    }
+}
+
+bool AAH_RXPlayer::Substream::shouldAbort(const char* log_tag) {
+    // If we have already encountered a fatal error, do nothing.  We are just
+    // waiting for our owner to shut us down now.
+    if (OK != status_) {
+        ALOGV("Skipping %s, substream has encountered fatal error (%d).",
+                log_tag, status_);
+        return true;
+    }
+
+    return false;
+}
+
+void AAH_RXPlayer::Substream::processPayloadStart(uint8_t* buf,
+                                                  uint32_t amt,
+                                                  int32_t ts_lower) {
+    uint32_t min_length = 6;
+
+    if (shouldAbort(__PRETTY_FUNCTION__)) {
+        return;
+    }
+
+    // Do we have a buffer in progress already?  If so, abort the buffer.  In
+    // theory, this should never happen.  If there were a discontinutity in the
+    // stream, the discon in the seq_nos at the RTP level should have already
+    // triggered a cleanup of the buffer in progress.  To see a problem at this
+    // level is an indication either of a bug in the transmitter, or some form
+    // of terrible corruption/tampering on the wire.
+    if (NULL != buffer_in_progress_) {
+        ALOGE("processPayloadStart is aborting payload already in progress.");
+        cleanupBufferInProgress();
+    }
+
+    // Parse enough of the header to know where we stand.  Since this is a
+    // payload start, it should begin with a TRTP header which has to be at
+    // least 6 bytes long.
+    if (amt < min_length) {
+        ALOGV("Discarding payload too short to contain TRTP header (len = %u)",
+                amt);
+        return;
+    }
+
+    // Check the TRTP version number.
+    if (0x01 != buf[0]) {
+        ALOGV("Unexpected TRTP version (%u) in header.  Expected %u.",
+                buf[0], 1);
+        return;
+    }
+
+    // Extract the substream type field and make sure its one we understand (and
+    // one that does not conflict with any previously received substream type.
+    uint8_t header_type = (buf[1] >> 4) & 0xF;
+    switch (header_type) {
+        case 0x01:
+            // Audio, yay!  Just break.  We understand audio payloads.
+            break;
+        case 0x02:
+            ALOGV("RXed packet with unhandled TRTP header type (Video).");
+            return;
+        case 0x03:
+            ALOGV("RXed packet with unhandled TRTP header type (Subpicture).");
+            return;
+        case 0x04:
+            ALOGV("RXed packet with unhandled TRTP header type (Control).");
+            return;
+        default:
+            ALOGV("RXed packet with unhandled TRTP header type (%u).",
+                    header_type);
+            return;
+    }
+
+    if (substream_details_known_ && (header_type != substream_type_)) {
+        ALOGV("RXed TRTP Payload for SSRC=0x%08x where header type (%u) does not"
+              " match previously received header type (%u)",
+              ssrc_, header_type, substream_type_);
+        return;
+    }
+
+    // Check the flags to see if there is another 32 bits of timestamp present.
+    uint32_t trtp_header_len = 6;
+    bool ts_valid = buf[1] & 0x1;
+    if (ts_valid) {
+        min_length += 4;
+        trtp_header_len += 4;
+        if (amt < min_length) {
+            ALOGV("Discarding payload too short to contain TRTP timestamp"
+                  " (len = %u)", amt);
+            return;
+        }
+    }
+
+    // Extract the TRTP length field and sanity check it.
+    uint32_t trtp_len;
+    trtp_len = (static_cast<uint32_t>(buf[2]) << 24) |
+        (static_cast<uint32_t>(buf[3]) << 16) |
+        (static_cast<uint32_t>(buf[4]) <<  8) |
+        static_cast<uint32_t>(buf[5]);
+    if (trtp_len < min_length) {
+        ALOGV("TRTP length (%u) is too short to be valid.  Must be at least %u"
+              " bytes.", trtp_len, min_length);
+        return;
+    }
+
+    // Extract the rest of the timestamp field if valid.
+    int64_t ts = 0;
+    uint32_t parse_offset = 6;
+    if (ts_valid) {
+        ts = (static_cast<int64_t>(buf[parse_offset    ]) << 56) |
+            (static_cast<int64_t>(buf[parse_offset + 1]) << 48) |
+            (static_cast<int64_t>(buf[parse_offset + 2]) << 40) |
+            (static_cast<int64_t>(buf[parse_offset + 3]) << 32);
+        ts |= ts_lower;
+        parse_offset += 4;
+    }
+
+    // Check the flags to see if there is another 24 bytes of timestamp
+    // transformation present.
+    if (buf[1] & 0x2) {
+        min_length += 24;
+        parse_offset += 24;
+        trtp_header_len += 24;
+        if (amt < min_length) {
+            ALOGV("Discarding payload too short to contain TRTP timestamp"
+                  " transformation (len = %u)", amt);
+            return;
+        }
+    }
+
+    // TODO : break the parsing into individual parsers for the different
+    // payload types (audio, video, etc).
+    //
+    // At this point in time, we know that this is audio.  Go ahead and parse
+    // the basic header, check the codec type, and find the payload portion of
+    // the packet.
+    min_length += 3;
+    if (trtp_len < min_length) {
+        ALOGV("TRTP length (%u) is too short to be a valid audio payload.  Must"
+              " be at least %u bytes.", trtp_len, min_length);
+        return;
+    }
+
+    if (amt < min_length) {
+        ALOGV("TRTP porttion of RTP payload (%u bytes) too small to contain"
+              " entire TRTP header.  TRTP does not currently support fragmenting"
+              " TRTP headers across RTP payloads", amt);
+        return;
+    }
+
+    uint8_t codec_type = buf[parse_offset    ];
+    uint8_t flags      = buf[parse_offset + 1];
+    uint8_t volume     = buf[parse_offset + 2];
+    parse_offset += 3;
+    trtp_header_len += 3;
+
+    if (!setupSubstreamType(header_type, codec_type)) {
+        return;
+    }
+
+    if (decoder_ != NULL) {
+        decoder_->setRenderVolume(volume);
+    }
+
+    // TODO : move all of the constant flag and offset definitions for TRTP up
+    // into some sort of common header file.
+    if (waiting_for_rap_ && !(flags & 0x08)) {
+        ALOGV("Dropping non-RAP TRTP Audio Payload while waiting for RAP.");
+        return;
+    }
+
+    if (flags & 0x10) {
+        ALOGV("Dropping TRTP Audio Payload with aux codec data present (only"
+              " handle MP3 right now, and it has no aux data)");
+        return;
+    }
+
+    // OK - everything left is just payload.  Compute the payload size, start
+    // the buffer in progress and pack as much payload as we can into it.  If
+    // the payload is finished once we are done, go ahead and send the payload
+    // to the decoder.
+    expected_buffer_size_ = trtp_len - trtp_header_len;
+    if (!expected_buffer_size_) {
+        ALOGV("Dropping TRTP Audio Payload with 0 Access Unit length");
+        return;
+    }
+
+    CHECK(amt >= trtp_header_len);
+    uint32_t todo = amt - trtp_header_len;
+    if (expected_buffer_size_ < todo) {
+        ALOGV("Extra data (%u > %u) present in initial TRTP Audio Payload;"
+              " dropping payload.", todo, expected_buffer_size_);
+        return;
+    }
+
+    buffer_filled_ = 0;
+    buffer_in_progress_ = new MediaBuffer(expected_buffer_size_);
+    if ((NULL == buffer_in_progress_) ||
+            (NULL == buffer_in_progress_->data())) {
+        ALOGV("Failed to allocate MediaBuffer of length %u",
+                expected_buffer_size_);
+        cleanupBufferInProgress();
+        return;
+    }
+
+    sp<MetaData> meta = buffer_in_progress_->meta_data();
+    if (meta == NULL) {
+        ALOGV("Missing metadata structure in allocated MediaBuffer; dropping"
+              " payload");
+        cleanupBufferInProgress();
+        return;
+    }
+
+    // TODO : set this based on the codec type indicated in the TRTP stream.
+    // Right now, we only support MP3, so the choice is obvious.
+    meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+    if (ts_valid) {
+        meta->setInt64(kKeyTime, ts);
+    }
+
+    if (amt > 0) {
+        uint8_t* tgt =
+            reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
+        memcpy(tgt + buffer_filled_, buf + trtp_header_len, todo);
+        buffer_filled_ += amt;
+    }
+
+    if (buffer_filled_ >= expected_buffer_size_) {
+        processCompletedBuffer();
+    }
+}
+
+void AAH_RXPlayer::Substream::processPayloadCont(uint8_t* buf,
+                                                 uint32_t amt) {
+    if (shouldAbort(__PRETTY_FUNCTION__)) {
+        return;
+    }
+
+    if (NULL == buffer_in_progress_) {
+        ALOGV("TRTP Receiver skipping payload continuation; no buffer currently"
+              " in progress.");
+        return;
+    }
+
+    CHECK(buffer_filled_ < expected_buffer_size_);
+    uint32_t buffer_left = expected_buffer_size_ - buffer_filled_;
+    if (amt > buffer_left) {
+        ALOGV("Extra data (%u > %u) present in continued TRTP Audio Payload;"
+              " dropping payload.", amt, buffer_left);
+        cleanupBufferInProgress();
+        return;
+    }
+
+    if (amt > 0) {
+        uint8_t* tgt =
+            reinterpret_cast<uint8_t*>(buffer_in_progress_->data());
+        memcpy(tgt + buffer_filled_, buf, amt);
+        buffer_filled_ += amt;
+    }
+
+    if (buffer_filled_ >= expected_buffer_size_) {
+        processCompletedBuffer();
+    }
+}
+
+void AAH_RXPlayer::Substream::processCompletedBuffer() {
+    const uint8_t* buffer_data = NULL;
+    int sample_rate;
+    int channel_count;
+    size_t frame_size;
+    status_t res;
+
+    CHECK(NULL != buffer_in_progress_);
+
+    if (decoder_ == NULL) {
+        ALOGV("Dropping complete buffer, no decoder pump allocated");
+        goto bailout;
+    }
+
+    buffer_data = reinterpret_cast<const uint8_t*>(buffer_in_progress_->data());
+    if (buffer_in_progress_->size() < 4) {
+        ALOGV("MP3 payload too short to contain header, dropping payload.");
+        goto bailout;
+    }
+
+    // Extract the channel count and the sample rate from the MP3 header.  The
+    // stagefright MP3 requires that these be delivered before decoing can
+    // begin.
+    if (!GetMPEGAudioFrameSize(U32_AT(buffer_data),
+                               &frame_size,
+                               &sample_rate,
+                               &channel_count,
+                               NULL,
+                               NULL)) {
+        ALOGV("Failed to parse MP3 header in payload, droping payload.");
+        goto bailout;
+    }
+
+
+    // Make sure that our substream metadata is set up properly.  If there has
+    // been a format change, be sure to reset the underlying decoder.  In
+    // stagefright, it seems like the only way to do this is to destroy and
+    // recreate the decoder.
+    if (substream_meta_ == NULL) {
+        substream_meta_ = new MetaData();
+
+        if (substream_meta_ == NULL) {
+            ALOGE("Failed to allocate MetaData structure for substream");
+            goto bailout;
+        }
+
+        substream_meta_->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
+        substream_meta_->setInt32  (kKeyChannelCount, channel_count);
+        substream_meta_->setInt32  (kKeySampleRate,   sample_rate);
+    } else {
+        int32_t prev_sample_rate;
+        int32_t prev_channel_count;
+        substream_meta_->findInt32(kKeySampleRate,   &prev_sample_rate);
+        substream_meta_->findInt32(kKeyChannelCount, &prev_channel_count);
+
+        if ((prev_channel_count != channel_count) ||
+            (prev_sample_rate   != sample_rate)) {
+            ALOGW("Format change detected, forcing decoder reset.");
+            cleanupDecoder();
+
+            substream_meta_->setInt32(kKeyChannelCount, channel_count);
+            substream_meta_->setInt32(kKeySampleRate,   sample_rate);
+        }
+    }
+
+    // If our decoder has not be set up, do so now.
+    res = decoder_->init(substream_meta_);
+    if (OK != res) {
+        ALOGE("Failed to init decoder (res = %d)", res);
+        cleanupDecoder();
+        substream_meta_ = NULL;
+        goto bailout;
+    }
+
+    // Queue the payload for decode.
+    res = decoder_->queueForDecode(buffer_in_progress_);
+
+    if (res != OK) {
+        ALOGD("Failed to queue payload for decode, resetting decoder pump!"
+              " (res = %d)", res);
+        status_ = res;
+        cleanupDecoder();
+        cleanupBufferInProgress();
+    }
+
+    // NULL out buffer_in_progress before calling the cleanup helper.
+    //
+    // MediaBuffers use something of a hybrid ref-counting pattern which prevent
+    // the AAH_DecoderPump's input queue from adding their own reference to the
+    // MediaBuffer.  MediaBuffers start life with a reference count of 0, as
+    // well as an observer which starts as NULL.  Before being given an
+    // observer, the ref count cannot be allowed to become non-zero as it will
+    // cause calls to release() to assert.  Basically, before a MediaBuffer has
+    // an observer, they behave like non-ref counted obects where release()
+    // serves the roll of delete.  After a MediaBuffer has an observer, they
+    // become more like ref counted objects where add ref and release can be
+    // used, and when the ref count hits zero, the MediaBuffer is handed off to
+    // the observer.
+    //
+    // Given all of this, when we give the buffer to the decoder pump to wait in
+    // the to-be-processed queue, the decoder cannot add a ref to the buffer as
+    // it would in a traditional ref counting system.  Instead it needs to
+    // "steal" the non-existent ref.  In the case of queue failure, we need to
+    // make certain to release this non-existent reference so that the buffer is
+    // cleaned up during the cleanupBufferInProgress helper.  In the case of a
+    // successful queue operation, we need to make certain that the
+    // cleanupBufferInProgress helper does not release the buffer since it needs
+    // to remain alive in the queue.  We acomplish this by NULLing out the
+    // buffer pointer before calling the cleanup helper.
+    buffer_in_progress_ = NULL;
+
+bailout:
+    cleanupBufferInProgress();
+}
+
+
+void AAH_RXPlayer::Substream::processTSTransform(const LinearTransform& trans) {
+    if (decoder_ != NULL) {
+        decoder_->setRenderTSTransform(trans);
+    }
+}
+
+bool AAH_RXPlayer::Substream::isAboutToUnderflow() {
+    if (decoder_ == NULL) {
+        return false;
+    }
+
+    return decoder_->isAboutToUnderflow(kAboutToUnderflowThreshold);
+}
+
+bool AAH_RXPlayer::Substream::setupSubstreamType(uint8_t substream_type,
+                                                 uint8_t codec_type) {
+    // Sanity check the codec type.  Right now we only support MP3.  Also check
+    // for conflicts with previously delivered codec types.
+    if (substream_details_known_ && (codec_type != codec_type_)) {
+        ALOGV("RXed TRTP Payload for SSRC=0x%08x where codec type (%u) does not"
+              " match previously received codec type (%u)",
+              ssrc_, codec_type, codec_type_);
+        return false;
+    }
+
+    if (codec_type != 0x03) {
+        ALOGV("RXed TRTP Audio Payload for SSRC=0x%08x with unsupported codec"
+              " type (%u)", ssrc_, codec_type);
+        return false;
+    }
+
+    if (!substream_details_known_) {
+        substream_type_ = substream_type;
+        codec_type_ = codec_type;
+        substream_details_known_ = true;
+    }
+
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.cpp b/media/libaah_rtp/aah_tx_packet.cpp
new file mode 100644
index 0000000..3f6e0e9
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_packet.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <string.h>
+
+#include <media/stagefright/foundation/ADebug.h>
+
+#include "aah_tx_packet.h"
+
+namespace android {
+
+const int TRTPPacket::kRTPHeaderLen;
+const uint32_t TRTPPacket::kTRTPEpochMask;
+
+TRTPPacket::~TRTPPacket() {
+    delete mPacket;
+}
+
+/*** TRTP packet properties ***/
+
+void TRTPPacket::setSeqNumber(uint16_t val) {
+    mSeqNumber = val;
+
+    if (mIsPacked) {
+        const int kTRTPSeqNumberOffset = 2;
+        uint16_t* buf = reinterpret_cast<uint16_t*>(
+            mPacket + kTRTPSeqNumberOffset);
+        *buf = htons(mSeqNumber);
+    }
+}
+
+uint16_t TRTPPacket::getSeqNumber() const {
+    return mSeqNumber;
+}
+
+void TRTPPacket::setPTS(int64_t val) {
+    CHECK(!mIsPacked);
+    mPTS = val;
+    mPTSValid = true;
+}
+
+int64_t TRTPPacket::getPTS() const {
+    return mPTS;
+}
+
+void TRTPPacket::setEpoch(uint32_t val) {
+    mEpoch = val;
+
+    if (mIsPacked) {
+        const int kTRTPEpochOffset = 8;
+        uint32_t* buf = reinterpret_cast<uint32_t*>(
+            mPacket + kTRTPEpochOffset);
+        uint32_t val = ntohl(*buf);
+        val &= ~(kTRTPEpochMask << kTRTPEpochShift);
+        val |= (mEpoch & kTRTPEpochMask) << kTRTPEpochShift;
+        *buf = htonl(val);
+    }
+}
+
+void TRTPPacket::setProgramID(uint16_t val) {
+    CHECK(!mIsPacked);
+    mProgramID = val;
+}
+
+void TRTPPacket::setSubstreamID(uint16_t val) {
+    CHECK(!mIsPacked);
+    mSubstreamID = val;
+}
+
+
+void TRTPPacket::setClockTransform(const LinearTransform& trans) {
+    CHECK(!mIsPacked);
+    mClockTranform = trans;
+    mClockTranformValid = true;
+}
+
+uint8_t* TRTPPacket::getPacket() const {
+    CHECK(mIsPacked);
+    return mPacket;
+}
+
+int TRTPPacket::getPacketLen() const {
+    CHECK(mIsPacked);
+    return mPacketLen;
+}
+
+void TRTPPacket::setExpireTime(nsecs_t val) {
+    CHECK(!mIsPacked);
+    mExpireTime = val;
+}
+
+nsecs_t TRTPPacket::getExpireTime() const {
+    return mExpireTime;
+}
+
+/*** TRTP audio packet properties ***/
+
+void TRTPAudioPacket::setCodecType(TRTPAudioCodecType val) {
+    CHECK(!mIsPacked);
+    mCodecType = val;
+}
+
+void TRTPAudioPacket::setRandomAccessPoint(bool val) {
+    CHECK(!mIsPacked);
+    mRandomAccessPoint = val;
+}
+
+void TRTPAudioPacket::setDropable(bool val) {
+    CHECK(!mIsPacked);
+    mDropable = val;
+}
+
+void TRTPAudioPacket::setDiscontinuity(bool val) {
+    CHECK(!mIsPacked);
+    mDiscontinuity = val;
+}
+
+void TRTPAudioPacket::setEndOfStream(bool val) {
+    CHECK(!mIsPacked);
+    mEndOfStream = val;
+}
+
+void TRTPAudioPacket::setVolume(uint8_t val) {
+    CHECK(!mIsPacked);
+    mVolume = val;
+}
+
+void TRTPAudioPacket::setAccessUnitData(void* data, int len) {
+    CHECK(!mIsPacked);
+    mAccessUnitData = data;
+    mAccessUnitLen = len;
+}
+
+/*** TRTP control packet properties ***/
+
+void TRTPControlPacket::setCommandID(TRTPCommandID val) {
+    CHECK(!mIsPacked);
+    mCommandID = val;
+}
+
+/*** TRTP packet serializers ***/
+
+void TRTPPacket::writeU8(uint8_t*& buf, uint8_t val) {
+    *buf = val;
+    buf++;
+}
+
+void TRTPPacket::writeU16(uint8_t*& buf, uint16_t val) {
+    *reinterpret_cast<uint16_t*>(buf) = htons(val);
+    buf += 2;
+}
+
+void TRTPPacket::writeU32(uint8_t*& buf, uint32_t val) {
+    *reinterpret_cast<uint32_t*>(buf) = htonl(val);
+    buf += 4;
+}
+
+void TRTPPacket::writeU64(uint8_t*& buf, uint64_t val) {
+    buf[0] = static_cast<uint8_t>(val >> 56);
+    buf[1] = static_cast<uint8_t>(val >> 48);
+    buf[2] = static_cast<uint8_t>(val >> 40);
+    buf[3] = static_cast<uint8_t>(val >> 32);
+    buf[4] = static_cast<uint8_t>(val >> 24);
+    buf[5] = static_cast<uint8_t>(val >> 16);
+    buf[6] = static_cast<uint8_t>(val >>  8);
+    buf[7] = static_cast<uint8_t>(val);
+    buf += 8;
+}
+
+void TRTPPacket::writeTRTPHeader(uint8_t*& buf,
+                                 bool isFirstFragment,
+                                 int totalPacketLen) {
+    // RTP header
+    writeU8(buf,
+            ((mVersion & 0x03) << 6) |
+            (static_cast<int>(mPadding) << 5) |
+            (static_cast<int>(mExtension) << 4) |
+            (mCsrcCount & 0x0F));
+    writeU8(buf,
+            (static_cast<int>(isFirstFragment) << 7) |
+            (mPayloadType & 0x7F));
+    writeU16(buf, mSeqNumber);
+    if (isFirstFragment && mPTSValid) {
+        writeU32(buf, mPTS & 0xFFFFFFFF);
+    } else {
+        writeU32(buf, 0);
+    }
+    writeU32(buf,
+            ((mEpoch & kTRTPEpochMask) << kTRTPEpochShift) |
+            ((mProgramID & 0x1F) << 5) |
+            (mSubstreamID & 0x1F));
+
+    // TRTP header
+    writeU8(buf, mTRTPVersion);
+    writeU8(buf,
+            ((mTRTPHeaderType & 0x0F) << 4) |
+            (mClockTranformValid ? 0x02 : 0x00) |
+            (mPTSValid ? 0x01 : 0x00));
+    writeU32(buf, totalPacketLen - kRTPHeaderLen);
+    if (mPTSValid) {
+        writeU32(buf, mPTS >> 32);
+    }
+
+    if (mClockTranformValid) {
+        writeU64(buf, mClockTranform.a_zero);
+        writeU32(buf, mClockTranform.a_to_b_numer);
+        writeU32(buf, mClockTranform.a_to_b_denom);
+        writeU64(buf, mClockTranform.b_zero);
+    }
+}
+
+bool TRTPAudioPacket::pack() {
+    if (mIsPacked) {
+        return false;
+    }
+
+    int packetLen = kRTPHeaderLen +
+                    mAccessUnitLen +
+                    TRTPHeaderLen();
+
+    // TODO : support multiple fragments
+    const int kMaxUDPPayloadLen = 65507;
+    if (packetLen > kMaxUDPPayloadLen) {
+        return false;
+    }
+
+    mPacket = new uint8_t[packetLen];
+    if (!mPacket) {
+        return false;
+    }
+
+    mPacketLen = packetLen;
+
+    uint8_t* cur = mPacket;
+
+    writeTRTPHeader(cur, true, packetLen);
+    writeU8(cur, mCodecType);
+    writeU8(cur,
+            (static_cast<int>(mRandomAccessPoint) << 3) |
+            (static_cast<int>(mDropable) << 2) |
+            (static_cast<int>(mDiscontinuity) << 1) |
+            (static_cast<int>(mEndOfStream)));
+    writeU8(cur, mVolume);
+
+    memcpy(cur, mAccessUnitData, mAccessUnitLen);
+
+    mIsPacked = true;
+    return true;
+}
+
+int TRTPPacket::TRTPHeaderLen() const {
+    // 6 bytes for version, payload type, flags and length.  An additional 4 if
+    // there are upper timestamp bits present and another 24 if there is a clock
+    // transformation present.
+    return 6 +
+           (mClockTranformValid ? 24 : 0) +
+           (mPTSValid ? 4 : 0);
+}
+
+int TRTPAudioPacket::TRTPHeaderLen() const {
+    // TRTPPacket::TRTPHeaderLen() for the base TRTPHeader.  3 bytes for audio's
+    // codec type, flags and volume field.  Another 5 bytes if the codec type is
+    // PCM and we are sending sample rate/channel count. as well as however long
+    // the aux data (if present) is.
+
+    int pcmParamLength;
+    switch(mCodecType) {
+        case kCodecPCMBigEndian:
+        case kCodecPCMLittleEndian:
+            pcmParamLength = 5;
+            break;
+
+        default:
+            pcmParamLength = 0;
+            break;
+    }
+
+
+    // TODO : properly compute aux data length.  Currently, nothing
+    // uses aux data, so its length is always 0.
+    int auxDataLength = 0;
+    return TRTPPacket::TRTPHeaderLen() +
+           3 +
+           auxDataLength +
+           pcmParamLength;
+}
+
+bool TRTPControlPacket::pack() {
+    if (mIsPacked) {
+        return false;
+    }
+
+    // command packets contain a 2-byte command ID
+    int packetLen = kRTPHeaderLen +
+                    TRTPHeaderLen() +
+                    2;
+
+    mPacket = new uint8_t[packetLen];
+    if (!mPacket) {
+        return false;
+    }
+
+    mPacketLen = packetLen;
+
+    uint8_t* cur = mPacket;
+
+    writeTRTPHeader(cur, true, packetLen);
+    writeU16(cur, mCommandID);
+
+    mIsPacked = true;
+    return true;
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_tx_packet.h b/media/libaah_rtp/aah_tx_packet.h
new file mode 100644
index 0000000..833803e
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_packet.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAH_TX_PACKET_H__
+#define __AAH_TX_PACKET_H__
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/LinearTransform.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
+
+namespace android {
+
+class TRTPPacket : public RefBase {
+  protected:
+    enum TRTPHeaderType {
+        kHeaderTypeAudio = 1,
+        kHeaderTypeVideo = 2,
+        kHeaderTypeSubpicture = 3,
+        kHeaderTypeControl = 4,
+    };
+
+    TRTPPacket(TRTPHeaderType headerType)
+        : mIsPacked(false)
+        , mVersion(2)
+        , mPadding(false)
+        , mExtension(false)
+        , mCsrcCount(0)
+        , mPayloadType(100)
+        , mSeqNumber(0)
+        , mPTSValid(false)
+        , mPTS(0)
+        , mEpoch(0)
+        , mProgramID(0)
+        , mSubstreamID(0)
+        , mClockTranformValid(false)
+        , mTRTPVersion(1)
+        , mTRTPLength(0)
+        , mTRTPHeaderType(headerType)
+        , mPacket(NULL)
+        , mPacketLen(0) { }
+
+  public:
+    virtual ~TRTPPacket();
+
+    void setSeqNumber(uint16_t val);
+    uint16_t getSeqNumber() const;
+
+    void setPTS(int64_t val);
+    int64_t getPTS() const;
+
+    void setEpoch(uint32_t val);
+    void setProgramID(uint16_t val);
+    void setSubstreamID(uint16_t val);
+    void setClockTransform(const LinearTransform& trans);
+
+    uint8_t* getPacket() const;
+    int getPacketLen() const;
+
+    void setExpireTime(nsecs_t val);
+    nsecs_t getExpireTime() const;
+
+    virtual bool pack() = 0;
+
+    // mask for the number of bits in a TRTP epoch
+    static const uint32_t kTRTPEpochMask = (1 << 22) - 1;
+    static const int kTRTPEpochShift = 10;
+
+  protected:
+    static const int kRTPHeaderLen = 12;
+    virtual int TRTPHeaderLen() const;
+
+    void writeTRTPHeader(uint8_t*& buf,
+                         bool isFirstFragment,
+                         int totalPacketLen);
+
+    void writeU8(uint8_t*& buf, uint8_t val);
+    void writeU16(uint8_t*& buf, uint16_t val);
+    void writeU32(uint8_t*& buf, uint32_t val);
+    void writeU64(uint8_t*& buf, uint64_t val);
+
+    bool mIsPacked;
+
+    uint8_t mVersion;
+    bool mPadding;
+    bool mExtension;
+    uint8_t mCsrcCount;
+    uint8_t mPayloadType;
+    uint16_t mSeqNumber;
+    bool mPTSValid;
+    int64_t  mPTS;
+    uint32_t mEpoch;
+    uint16_t mProgramID;
+    uint16_t mSubstreamID;
+    LinearTransform mClockTranform;
+    bool mClockTranformValid;
+    uint8_t mTRTPVersion;
+    uint32_t mTRTPLength;
+    TRTPHeaderType mTRTPHeaderType;
+
+    uint8_t* mPacket;
+    int mPacketLen;
+
+    nsecs_t mExpireTime;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TRTPPacket);
+};
+
+class TRTPAudioPacket : public TRTPPacket {
+  public:
+    TRTPAudioPacket()
+        : TRTPPacket(kHeaderTypeAudio)
+        , mCodecType(kCodecInvalid)
+        , mRandomAccessPoint(false)
+        , mDropable(false)
+        , mDiscontinuity(false)
+        , mEndOfStream(false)
+        , mVolume(0)
+        , mAccessUnitData(NULL) { }
+
+    enum TRTPAudioCodecType {
+        kCodecInvalid = 0,
+        kCodecPCMBigEndian = 1,
+        kCodecPCMLittleEndian = 2,
+        kCodecMPEG1Audio = 3,
+    };
+
+    void setCodecType(TRTPAudioCodecType val);
+    void setRandomAccessPoint(bool val);
+    void setDropable(bool val);
+    void setDiscontinuity(bool val);
+    void setEndOfStream(bool val);
+    void setVolume(uint8_t val);
+    void setAccessUnitData(void* data, int len);
+
+    virtual bool pack();
+
+  protected:
+    virtual int TRTPHeaderLen() const;
+
+  private:
+    TRTPAudioCodecType mCodecType;
+    bool mRandomAccessPoint;
+    bool mDropable;
+    bool mDiscontinuity;
+    bool mEndOfStream;
+    uint8_t mVolume;
+    void* mAccessUnitData;
+    int mAccessUnitLen;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TRTPAudioPacket);
+};
+
+class TRTPControlPacket : public TRTPPacket {
+  public:
+    TRTPControlPacket()
+        : TRTPPacket(kHeaderTypeControl)
+        , mCommandID(kCommandNop) {}
+
+    enum TRTPCommandID {
+        kCommandNop   = 1,
+        kCommandFlush = 2,
+        kCommandEOS   = 3,
+    };
+
+    void setCommandID(TRTPCommandID val);
+
+    virtual bool pack();
+
+  private:
+    TRTPCommandID mCommandID;
+
+    DISALLOW_EVIL_CONSTRUCTORS(TRTPControlPacket);
+};
+
+}  // namespace android
+
+#endif  // __AAH_TX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_tx_player.cpp b/media/libaah_rtp/aah_tx_player.cpp
new file mode 100644
index 0000000..a79a989
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_player.cpp
@@ -0,0 +1,1139 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <utils/Log.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+#include <netdb.h>
+#include <netinet/ip.h>
+
+#include <common_time/cc_helper.h>
+#include <media/IMediaPlayer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/FileSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MetaData.h>
+#include <utils/Timers.h>
+
+#include "aah_tx_packet.h"
+#include "aah_tx_player.h"
+
+namespace android {
+
+static int64_t kLowWaterMarkUs = 2000000ll;  // 2secs
+static int64_t kHighWaterMarkUs = 10000000ll;  // 10secs
+static const size_t kLowWaterMarkBytes = 40000;
+static const size_t kHighWaterMarkBytes = 200000;
+
+// When we start up, how much lead time should we put on the first access unit?
+static const int64_t kAAHStartupLeadTimeUs = 300000LL;
+
+// How much time do we attempt to lead the clock by in steady state?
+static const int64_t kAAHBufferTimeUs = 1000000LL;
+
+// how long do we keep data in our retransmit buffer after sending it.
+const int64_t AAH_TXPlayer::kAAHRetryKeepAroundTimeNs =
+    kAAHBufferTimeUs * 1100;
+
+sp<MediaPlayerBase> createAAH_TXPlayer() {
+    sp<MediaPlayerBase> ret = new AAH_TXPlayer();
+    return ret;
+}
+
+template <typename T> static T clamp(T val, T min, T max) {
+    if (val < min) {
+        return min;
+    } else if (val > max) {
+        return max;
+    } else {
+        return val;
+    }
+}
+
+struct AAH_TXEvent : public TimedEventQueue::Event {
+    AAH_TXEvent(AAH_TXPlayer *player,
+                void (AAH_TXPlayer::*method)()) : mPlayer(player)
+                                                , mMethod(method) {}
+
+  protected:
+    virtual ~AAH_TXEvent() {}
+
+    virtual void fire(TimedEventQueue *queue, int64_t /* now_us */) {
+        (mPlayer->*mMethod)();
+    }
+
+  private:
+    AAH_TXPlayer *mPlayer;
+    void (AAH_TXPlayer::*mMethod)();
+
+    AAH_TXEvent(const AAH_TXEvent &);
+    AAH_TXEvent& operator=(const AAH_TXEvent &);
+};
+
+AAH_TXPlayer::AAH_TXPlayer()
+        : mQueueStarted(false)
+        , mFlags(0)
+        , mExtractorFlags(0) {
+    DataSource::RegisterDefaultSniffers();
+
+    mBufferingEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onBufferingUpdate);
+    mBufferingEventPending = false;
+
+    mPumpAudioEvent = new AAH_TXEvent(this, &AAH_TXPlayer::onPumpAudio);
+    mPumpAudioEventPending = false;
+
+    reset_l();
+}
+
+AAH_TXPlayer::~AAH_TXPlayer() {
+    if (mQueueStarted) {
+        mQueue.stop();
+    }
+
+    reset_l();
+}
+
+void AAH_TXPlayer::cancelPlayerEvents(bool keepBufferingGoing) {
+    if (!keepBufferingGoing) {
+        mQueue.cancelEvent(mBufferingEvent->eventID());
+        mBufferingEventPending = false;
+
+        mQueue.cancelEvent(mPumpAudioEvent->eventID());
+        mPumpAudioEventPending = false;
+    }
+}
+
+status_t AAH_TXPlayer::initCheck() {
+    // Check for the presense of the common time service by attempting to query
+    // for CommonTime's frequency.  If we get an error back, we cannot talk to
+    // the service at all and should abort now.
+    status_t res;
+    uint64_t freq;
+    res = mCCHelper.getCommonFreq(&freq);
+    if (OK != res) {
+        ALOGE("Failed to connect to common time service! (res %d)", res);
+        return res;
+    }
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::setDataSource(
+        const char *url,
+        const KeyedVector<String8, String8> *headers) {
+    Mutex::Autolock autoLock(mLock);
+    return setDataSource_l(url, headers);
+}
+
+status_t AAH_TXPlayer::setDataSource_l(
+        const char *url,
+        const KeyedVector<String8, String8> *headers) {
+    reset_l();
+
+    // the URL must consist of "aahTX://" followed by the real URL of
+    // the data source
+    const char *kAAHPrefix = "aahTX://";
+    if (strncasecmp(url, kAAHPrefix, strlen(kAAHPrefix))) {
+        return INVALID_OPERATION;
+    }
+
+    mUri.setTo(url + strlen(kAAHPrefix));
+
+    if (headers) {
+        mUriHeaders = *headers;
+
+        ssize_t index = mUriHeaders.indexOfKey(String8("x-hide-urls-from-log"));
+        if (index >= 0) {
+            // Browser is in "incognito" mode, suppress logging URLs.
+
+            // This isn't something that should be passed to the server.
+            mUriHeaders.removeItemsAt(index);
+
+            mFlags |= INCOGNITO;
+        }
+    }
+
+    // The URL may optionally contain a "#" character followed by a Skyjam
+    // cookie.  Ideally the cookie header should just be passed in the headers
+    // argument, but the Java API for supplying headers is apparently not yet
+    // exposed in the SDK used by application developers.
+    const char kSkyjamCookieDelimiter = '#';
+    char* skyjamCookie = strrchr(mUri.string(), kSkyjamCookieDelimiter);
+    if (skyjamCookie) {
+        skyjamCookie++;
+        mUriHeaders.add(String8("Cookie"), String8(skyjamCookie));
+        mUri = String8(mUri.string(), skyjamCookie - mUri.string());
+    }
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::setDataSource(int fd, int64_t offset, int64_t length) {
+    Mutex::Autolock autoLock(mLock);
+
+    reset_l();
+
+    sp<DataSource> dataSource = new FileSource(dup(fd), offset, length);
+
+    status_t err = dataSource->initCheck();
+
+    if (err != OK) {
+        return err;
+    }
+
+    mFileSource = dataSource;
+
+    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+    if (extractor == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    return setDataSource_l(extractor);
+}
+
+status_t AAH_TXPlayer::setVideoSurface(const sp<Surface>& surface) {
+    return OK;
+}
+
+status_t AAH_TXPlayer::setVideoSurfaceTexture(
+        const sp<ISurfaceTexture>& surfaceTexture) {
+    return OK;
+}
+
+status_t AAH_TXPlayer::prepare() {
+    return INVALID_OPERATION;
+}
+
+status_t AAH_TXPlayer::prepareAsync() {
+    Mutex::Autolock autoLock(mLock);
+
+    return prepareAsync_l();
+}
+
+status_t AAH_TXPlayer::prepareAsync_l() {
+    if (mFlags & PREPARING) {
+        return UNKNOWN_ERROR;  // async prepare already pending
+    }
+
+    mAAH_Sender = AAH_TXSender::GetInstance();
+    if (mAAH_Sender == NULL) {
+        return NO_MEMORY;
+    }
+
+    if (!mQueueStarted) {
+        mQueue.start();
+        mQueueStarted = true;
+    }
+
+    mFlags |= PREPARING;
+    mAsyncPrepareEvent = new AAH_TXEvent(
+            this, &AAH_TXPlayer::onPrepareAsyncEvent);
+
+    mQueue.postEvent(mAsyncPrepareEvent);
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::finishSetDataSource_l() {
+    sp<DataSource> dataSource;
+
+    if (!strncasecmp("http://",  mUri.string(), 7) ||
+        !strncasecmp("https://", mUri.string(), 8)) {
+
+        mConnectingDataSource = HTTPBase::Create(
+                (mFlags & INCOGNITO)
+                    ? HTTPBase::kFlagIncognito
+                    : 0);
+
+        mLock.unlock();
+        status_t err = mConnectingDataSource->connect(mUri, &mUriHeaders);
+        mLock.lock();
+
+        if (err != OK) {
+            mConnectingDataSource.clear();
+
+            ALOGI("mConnectingDataSource->connect() returned %d", err);
+            return err;
+        }
+
+        mCachedSource = new NuCachedSource2(mConnectingDataSource);
+        mConnectingDataSource.clear();
+
+        dataSource = mCachedSource;
+
+        // We're going to prefill the cache before trying to instantiate
+        // the extractor below, as the latter is an operation that otherwise
+        // could block on the datasource for a significant amount of time.
+        // During that time we'd be unable to abort the preparation phase
+        // without this prefill.
+
+        mLock.unlock();
+
+        for (;;) {
+            status_t finalStatus;
+            size_t cachedDataRemaining =
+                mCachedSource->approxDataRemaining(&finalStatus);
+
+            if (finalStatus != OK ||
+                cachedDataRemaining >= kHighWaterMarkBytes ||
+                (mFlags & PREPARE_CANCELLED)) {
+                break;
+            }
+
+            usleep(200000);
+        }
+
+        mLock.lock();
+
+        if (mFlags & PREPARE_CANCELLED) {
+            ALOGI("Prepare cancelled while waiting for initial cache fill.");
+            return UNKNOWN_ERROR;
+        }
+    } else {
+        dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
+    }
+
+    if (dataSource == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+    if (extractor == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    return setDataSource_l(extractor);
+}
+
+status_t AAH_TXPlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
+    // Attempt to approximate overall stream bitrate by summing all
+    // tracks' individual bitrates, if not all of them advertise bitrate,
+    // we have to fail.
+
+    int64_t totalBitRate = 0;
+
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+        int32_t bitrate;
+        if (!meta->findInt32(kKeyBitRate, &bitrate)) {
+            totalBitRate = -1;
+            break;
+        }
+
+        totalBitRate += bitrate;
+    }
+
+    mBitrate = totalBitRate;
+
+    ALOGV("mBitrate = %lld bits/sec", mBitrate);
+
+    bool haveAudio = false;
+    for (size_t i = 0; i < extractor->countTracks(); ++i) {
+        sp<MetaData> meta = extractor->getTrackMetaData(i);
+
+        const char *mime;
+        CHECK(meta->findCString(kKeyMIMEType, &mime));
+
+        if (!strncasecmp(mime, "audio/", 6)) {
+            mAudioSource = extractor->getTrack(i);
+            CHECK(mAudioSource != NULL);
+            haveAudio = true;
+            break;
+        }
+    }
+
+    if (!haveAudio) {
+        return UNKNOWN_ERROR;
+    }
+
+    mExtractorFlags = extractor->flags();
+
+    return OK;
+}
+
+void AAH_TXPlayer::abortPrepare(status_t err) {
+    CHECK(err != OK);
+
+    notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+
+    mPrepareResult = err;
+    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
+    mPreparedCondition.broadcast();
+}
+
+void AAH_TXPlayer::onPrepareAsyncEvent() {
+    Mutex::Autolock autoLock(mLock);
+
+    if (mFlags & PREPARE_CANCELLED) {
+        ALOGI("prepare was cancelled before doing anything");
+        abortPrepare(UNKNOWN_ERROR);
+        return;
+    }
+
+    if (mUri.size() > 0) {
+        status_t err = finishSetDataSource_l();
+
+        if (err != OK) {
+            abortPrepare(err);
+            return;
+        }
+    }
+
+    mAudioSource->getFormat()->findInt64(kKeyDuration, &mDurationUs);
+
+    status_t err = mAudioSource->start();
+    if (err != OK) {
+        ALOGI("failed to start audio source, err=%d", err);
+        abortPrepare(err);
+        return;
+    }
+
+    mFlags |= PREPARING_CONNECTED;
+
+    if (mCachedSource != NULL) {
+        postBufferingEvent_l();
+    } else {
+        finishAsyncPrepare_l();
+    }
+}
+
+void AAH_TXPlayer::finishAsyncPrepare_l() {
+    notifyListener_l(MEDIA_PREPARED);
+
+    mPrepareResult = OK;
+    mFlags &= ~(PREPARING|PREPARE_CANCELLED|PREPARING_CONNECTED);
+    mFlags |= PREPARED;
+    mPreparedCondition.broadcast();
+}
+
+status_t AAH_TXPlayer::start() {
+    Mutex::Autolock autoLock(mLock);
+
+    mFlags &= ~CACHE_UNDERRUN;
+
+    return play_l();
+}
+
+status_t AAH_TXPlayer::play_l() {
+    if (mFlags & PLAYING) {
+        return OK;
+    }
+
+    if (!(mFlags & PREPARED)) {
+        return INVALID_OPERATION;
+    }
+
+    {
+        Mutex::Autolock lock(mEndpointLock);
+        if (!mEndpointValid) {
+            return INVALID_OPERATION;
+        }
+        if (!mEndpointRegistered) {
+            mProgramID = mAAH_Sender->registerEndpoint(mEndpoint);
+            mEndpointRegistered = true;
+        }
+    }
+
+    mFlags |= PLAYING;
+
+    updateClockTransform_l(false);
+
+    postPumpAudioEvent_l(-1);
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::stop() {
+    status_t ret = pause();
+    sendEOS_l();
+    return ret;
+}
+
+status_t AAH_TXPlayer::pause() {
+    Mutex::Autolock autoLock(mLock);
+
+    mFlags &= ~CACHE_UNDERRUN;
+
+    return pause_l();
+}
+
+status_t AAH_TXPlayer::pause_l(bool doClockUpdate) {
+    if (!(mFlags & PLAYING)) {
+        return OK;
+    }
+
+    cancelPlayerEvents(true /* keepBufferingGoing */);
+
+    mFlags &= ~PLAYING;
+
+    if (doClockUpdate) {
+        updateClockTransform_l(true);
+    }
+
+    return OK;
+}
+
+void AAH_TXPlayer::updateClockTransform_l(bool pause) {
+    // record the new pause status so that onPumpAudio knows what rate to apply
+    // when it initializes the transform
+    mPlayRateIsPaused = pause;
+
+    // if we haven't yet established a valid clock transform, then we can't
+    // do anything here
+    if (!mCurrentClockTransformValid) {
+        return;
+    }
+
+    // sample the current common time
+    int64_t commonTimeNow;
+    if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
+        ALOGE("updateClockTransform_l get common time failed");
+        mCurrentClockTransformValid = false;
+        return;
+    }
+
+    // convert the current common time to media time using the old
+    // transform
+    int64_t mediaTimeNow;
+    if (!mCurrentClockTransform.doReverseTransform(
+            commonTimeNow, &mediaTimeNow)) {
+        ALOGE("updateClockTransform_l reverse transform failed");
+        mCurrentClockTransformValid = false;
+        return;
+    }
+
+    // calculate a new transform that preserves the old transform's
+    // result for the current time
+    mCurrentClockTransform.a_zero = mediaTimeNow;
+    mCurrentClockTransform.b_zero = commonTimeNow;
+    mCurrentClockTransform.a_to_b_numer = 1;
+    mCurrentClockTransform.a_to_b_denom = pause ? 0 : 1;
+
+    // send a packet announcing the new transform
+    sp<TRTPControlPacket> packet = new TRTPControlPacket();
+    packet->setClockTransform(mCurrentClockTransform);
+    packet->setCommandID(TRTPControlPacket::kCommandNop);
+    queuePacketToSender_l(packet);
+}
+
+void AAH_TXPlayer::sendEOS_l() {
+    sp<TRTPControlPacket> packet = new TRTPControlPacket();
+    packet->setCommandID(TRTPControlPacket::kCommandEOS);
+    queuePacketToSender_l(packet);
+}
+
+bool AAH_TXPlayer::isPlaying() {
+    return (mFlags & PLAYING) || (mFlags & CACHE_UNDERRUN);
+}
+
+status_t AAH_TXPlayer::seekTo(int msec) {
+    if (mExtractorFlags & MediaExtractor::CAN_SEEK) {
+        Mutex::Autolock autoLock(mLock);
+        return seekTo_l(static_cast<int64_t>(msec) * 1000);
+    }
+
+    notifyListener_l(MEDIA_SEEK_COMPLETE);
+    return OK;
+}
+
+status_t AAH_TXPlayer::seekTo_l(int64_t timeUs) {
+    mIsSeeking = true;
+    mSeekTimeUs = timeUs;
+
+    mCurrentClockTransformValid = false;
+    mLastQueuedMediaTimePTSValid = false;
+
+    // send a flush command packet
+    sp<TRTPControlPacket> packet = new TRTPControlPacket();
+    packet->setCommandID(TRTPControlPacket::kCommandFlush);
+    queuePacketToSender_l(packet);
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::getCurrentPosition(int *msec) {
+    if (!msec) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mLock);
+
+    int position;
+
+    if (mIsSeeking) {
+        position = mSeekTimeUs / 1000;
+    } else if (mCurrentClockTransformValid) {
+        // sample the current common time
+        int64_t commonTimeNow;
+        if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
+            ALOGE("getCurrentPosition get common time failed");
+            return INVALID_OPERATION;
+        }
+
+        int64_t mediaTimeNow;
+        if (!mCurrentClockTransform.doReverseTransform(commonTimeNow,
+                    &mediaTimeNow)) {
+            ALOGE("getCurrentPosition reverse transform failed");
+            return INVALID_OPERATION;
+        }
+
+        position = static_cast<int>(mediaTimeNow / 1000);
+    } else {
+        position = 0;
+    }
+
+    int duration;
+    if (getDuration_l(&duration) == OK) {
+        *msec = clamp(position, 0, duration);
+    } else {
+        *msec = (position >= 0) ? position : 0;
+    }
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::getDuration(int* msec) {
+    if (!msec) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mLock);
+
+    return getDuration_l(msec);
+}
+
+status_t AAH_TXPlayer::getDuration_l(int* msec) {
+    if (mDurationUs < 0) {
+        return UNKNOWN_ERROR;
+    }
+
+    *msec = (mDurationUs + 500) / 1000;
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::reset() {
+    Mutex::Autolock autoLock(mLock);
+    reset_l();
+    return OK;
+}
+
+void AAH_TXPlayer::reset_l() {
+    if (mFlags & PREPARING) {
+        mFlags |= PREPARE_CANCELLED;
+        if (mConnectingDataSource != NULL) {
+            ALOGI("interrupting the connection process");
+            mConnectingDataSource->disconnect();
+        }
+
+        if (mFlags & PREPARING_CONNECTED) {
+            // We are basically done preparing, we're just buffering
+            // enough data to start playback, we can safely interrupt that.
+            finishAsyncPrepare_l();
+        }
+    }
+
+    while (mFlags & PREPARING) {
+        mPreparedCondition.wait(mLock);
+    }
+
+    cancelPlayerEvents();
+
+    sendEOS_l();
+
+    mCachedSource.clear();
+
+    if (mAudioSource != NULL) {
+        mAudioSource->stop();
+    }
+    mAudioSource.clear();
+
+    mFlags = 0;
+    mExtractorFlags = 0;
+
+    mDurationUs = -1;
+    mIsSeeking = false;
+    mSeekTimeUs = 0;
+
+    mUri.setTo("");
+    mUriHeaders.clear();
+
+    mFileSource.clear();
+
+    mBitrate = -1;
+
+    {
+        Mutex::Autolock lock(mEndpointLock);
+        if (mAAH_Sender != NULL && mEndpointRegistered) {
+            mAAH_Sender->unregisterEndpoint(mEndpoint);
+        }
+        mEndpointRegistered = false;
+        mEndpointValid = false;
+    }
+
+    mProgramID = 0;
+
+    mAAH_Sender.clear();
+    mLastQueuedMediaTimePTSValid = false;
+    mCurrentClockTransformValid = false;
+    mPlayRateIsPaused = false;
+
+    mTRTPVolume = 255;
+}
+
+status_t AAH_TXPlayer::setLooping(int loop) {
+    return OK;
+}
+
+player_type AAH_TXPlayer::playerType() {
+    return AAH_TX_PLAYER;
+}
+
+status_t AAH_TXPlayer::setParameter(int key, const Parcel &request) {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_TXPlayer::getParameter(int key, Parcel *reply) {
+    return ERROR_UNSUPPORTED;
+}
+
+status_t AAH_TXPlayer::invoke(const Parcel& request, Parcel *reply) {
+    if (!reply) {
+        return BAD_VALUE;
+    }
+
+    int32_t methodID;
+    status_t err = request.readInt32(&methodID);
+    if (err != android::OK) {
+        return err;
+    }
+
+    switch (methodID) {
+        case kInvokeSetAAHDstIPPort:
+        case kInvokeSetAAHConfigBlob: {
+            if (mEndpointValid) {
+                return INVALID_OPERATION;
+            }
+
+            String8 addr;
+            uint16_t port;
+
+            if (methodID == kInvokeSetAAHDstIPPort) {
+                addr = String8(request.readString16());
+
+                int32_t port32;
+                err = request.readInt32(&port32);
+                if (err != android::OK) {
+                    return err;
+                }
+                port = static_cast<uint16_t>(port32);
+            } else {
+                String8 blob(request.readString16());
+
+                char addr_buf[101];
+                if (sscanf(blob.string(), "V1:%100s %" SCNu16,
+                           addr_buf, &port) != 2) {
+                    return BAD_VALUE;
+                }
+                if (addr.setTo(addr_buf) != OK) {
+                    return NO_MEMORY;
+                }
+            }
+
+            struct hostent* ent = gethostbyname(addr.string());
+            if (ent == NULL) {
+                return ERROR_UNKNOWN_HOST;
+            }
+            if (!(ent->h_addrtype == AF_INET && ent->h_length == 4)) {
+                return BAD_VALUE;
+            }
+
+            Mutex::Autolock lock(mEndpointLock);
+            mEndpoint = AAH_TXSender::Endpoint(
+                        reinterpret_cast<struct in_addr*>(ent->h_addr)->s_addr,
+                        port);
+            mEndpointValid = true;
+            return OK;
+        };
+
+        default:
+            return INVALID_OPERATION;
+    }
+}
+
+status_t AAH_TXPlayer::getMetadata(const media::Metadata::Filter& ids,
+                                   Parcel* records) {
+    using media::Metadata;
+
+    Metadata metadata(records);
+
+    metadata.appendBool(Metadata::kPauseAvailable, true);
+    metadata.appendBool(Metadata::kSeekBackwardAvailable, false);
+    metadata.appendBool(Metadata::kSeekForwardAvailable, false);
+    metadata.appendBool(Metadata::kSeekAvailable, false);
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::setVolume(float leftVolume, float rightVolume) {
+    if (leftVolume != rightVolume) {
+        ALOGE("%s does not support per channel volume: %f, %f",
+              __PRETTY_FUNCTION__, leftVolume, rightVolume);
+    }
+
+    float volume = clamp(leftVolume, 0.0f, 1.0f);
+
+    Mutex::Autolock lock(mLock);
+    mTRTPVolume = static_cast<uint8_t>((leftVolume * 255.0) + 0.5);
+
+    return OK;
+}
+
+status_t AAH_TXPlayer::setAudioStreamType(audio_stream_type_t streamType) {
+    return OK;
+}
+
+void AAH_TXPlayer::notifyListener_l(int msg, int ext1, int ext2) {
+    sendEvent(msg, ext1, ext2);
+}
+
+bool AAH_TXPlayer::getBitrate_l(int64_t *bitrate) {
+    off64_t size;
+    if (mDurationUs >= 0 &&
+        mCachedSource != NULL &&
+        mCachedSource->getSize(&size) == OK) {
+        *bitrate = size * 8000000ll / mDurationUs;  // in bits/sec
+        return true;
+    }
+
+    if (mBitrate >= 0) {
+        *bitrate = mBitrate;
+        return true;
+    }
+
+    *bitrate = 0;
+
+    return false;
+}
+
+// Returns true iff cached duration is available/applicable.
+bool AAH_TXPlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
+    int64_t bitrate;
+
+    if (mCachedSource != NULL && getBitrate_l(&bitrate)) {
+        status_t finalStatus;
+        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
+                                        &finalStatus);
+        *durationUs = cachedDataRemaining * 8000000ll / bitrate;
+        *eos = (finalStatus != OK);
+        return true;
+    }
+
+    return false;
+}
+
+void AAH_TXPlayer::ensureCacheIsFetching_l() {
+    if (mCachedSource != NULL) {
+        mCachedSource->resumeFetchingIfNecessary();
+    }
+}
+
+void AAH_TXPlayer::postBufferingEvent_l() {
+    if (mBufferingEventPending) {
+        return;
+    }
+    mBufferingEventPending = true;
+    mQueue.postEventWithDelay(mBufferingEvent, 1000000ll);
+}
+
+void AAH_TXPlayer::postPumpAudioEvent_l(int64_t delayUs) {
+    if (mPumpAudioEventPending) {
+        return;
+    }
+    mPumpAudioEventPending = true;
+    mQueue.postEventWithDelay(mPumpAudioEvent, delayUs < 0 ? 10000 : delayUs);
+}
+
+void AAH_TXPlayer::onBufferingUpdate() {
+    Mutex::Autolock autoLock(mLock);
+    if (!mBufferingEventPending) {
+        return;
+    }
+    mBufferingEventPending = false;
+
+    if (mCachedSource != NULL) {
+        status_t finalStatus;
+        size_t cachedDataRemaining = mCachedSource->approxDataRemaining(
+                                        &finalStatus);
+        bool eos = (finalStatus != OK);
+
+        if (eos) {
+            if (finalStatus == ERROR_END_OF_STREAM) {
+                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+            }
+            if (mFlags & PREPARING) {
+                ALOGV("cache has reached EOS, prepare is done.");
+                finishAsyncPrepare_l();
+            }
+        } else {
+            int64_t bitrate;
+            if (getBitrate_l(&bitrate)) {
+                size_t cachedSize = mCachedSource->cachedSize();
+                int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
+
+                int percentage = (100.0 * (double) cachedDurationUs)
+                               / mDurationUs;
+                if (percentage > 100) {
+                    percentage = 100;
+                }
+
+                notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
+            } else {
+                // We don't know the bitrate of the stream, use absolute size
+                // limits to maintain the cache.
+
+                if ((mFlags & PLAYING) &&
+                    !eos &&
+                    (cachedDataRemaining < kLowWaterMarkBytes)) {
+                    ALOGI("cache is running low (< %d) , pausing.",
+                          kLowWaterMarkBytes);
+                    mFlags |= CACHE_UNDERRUN;
+                    pause_l();
+                    ensureCacheIsFetching_l();
+                    notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
+                } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
+                    if (mFlags & CACHE_UNDERRUN) {
+                        ALOGI("cache has filled up (> %d), resuming.",
+                              kHighWaterMarkBytes);
+                        mFlags &= ~CACHE_UNDERRUN;
+                        play_l();
+                        notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+                    } else if (mFlags & PREPARING) {
+                        ALOGV("cache has filled up (> %d), prepare is done",
+                              kHighWaterMarkBytes);
+                        finishAsyncPrepare_l();
+                    }
+                }
+            }
+        }
+    }
+
+    int64_t cachedDurationUs;
+    bool eos;
+    if (getCachedDuration_l(&cachedDurationUs, &eos)) {
+        ALOGV("cachedDurationUs = %.2f secs, eos=%d",
+              cachedDurationUs / 1E6, eos);
+
+        if ((mFlags & PLAYING) &&
+            !eos &&
+            (cachedDurationUs < kLowWaterMarkUs)) {
+            ALOGI("cache is running low (%.2f secs) , pausing.",
+                  cachedDurationUs / 1E6);
+            mFlags |= CACHE_UNDERRUN;
+            pause_l();
+            ensureCacheIsFetching_l();
+            notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
+        } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
+            if (mFlags & CACHE_UNDERRUN) {
+                ALOGI("cache has filled up (%.2f secs), resuming.",
+                      cachedDurationUs / 1E6);
+                mFlags &= ~CACHE_UNDERRUN;
+                play_l();
+                notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+            } else if (mFlags & PREPARING) {
+                ALOGV("cache has filled up (%.2f secs), prepare is done",
+                        cachedDurationUs / 1E6);
+                finishAsyncPrepare_l();
+            }
+        }
+    }
+
+    postBufferingEvent_l();
+}
+
+void AAH_TXPlayer::onPumpAudio() {
+    while (true) {
+        Mutex::Autolock autoLock(mLock);
+        // If this flag is clear, its because someone has externally canceled
+        // this pump operation (probably because we a resetting/shutting down).
+        // Get out immediately, do not reschedule ourselves.
+        if (!mPumpAudioEventPending) {
+            return;
+        }
+
+        // Start by checking if there is still work to be doing.  If we have
+        // never queued a payload (so we don't know what the last queued PTS is)
+        // or we have never established a MediaTime->CommonTime transformation,
+        // then we have work to do (one time through this loop should establish
+        // both).  Otherwise, we want to keep a fixed amt of presentation time
+        // worth of data buffered.  If we cannot get common time (service is
+        // unavailable, or common time is undefined)) then we don't have a lot
+        // of good options here.  For now, signal an error up to the app level
+        // and shut down the transmission pump.
+        int64_t commonTimeNow;
+        if (OK != mCCHelper.getCommonTime(&commonTimeNow)) {
+            // Failed to get common time; either the service is down or common
+            // time is not synced.  Raise an error and shutdown the player.
+            ALOGE("*** Cannot pump audio, unable to fetch common time."
+                  "  Shutting down.");
+            notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, UNKNOWN_ERROR);
+            mPumpAudioEventPending = false;
+            break;
+        }
+
+        if (mCurrentClockTransformValid && mLastQueuedMediaTimePTSValid) {
+            int64_t mediaTimeNow;
+            bool conversionResult = mCurrentClockTransform.doReverseTransform(
+                                        commonTimeNow,
+                                        &mediaTimeNow);
+            CHECK(conversionResult);
+
+            if ((mediaTimeNow +
+                 kAAHBufferTimeUs -
+                 mLastQueuedMediaTimePTS) <= 0) {
+                break;
+            }
+        }
+
+        MediaSource::ReadOptions options;
+        if (mIsSeeking) {
+            options.setSeekTo(mSeekTimeUs);
+        }
+
+        MediaBuffer* mediaBuffer;
+        status_t err = mAudioSource->read(&mediaBuffer, &options);
+        if (err != NO_ERROR) {
+            if (err == ERROR_END_OF_STREAM) {
+                ALOGI("*** %s reached end of stream", __PRETTY_FUNCTION__);
+                notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+                notifyListener_l(MEDIA_PLAYBACK_COMPLETE);
+                pause_l(false);
+                sendEOS_l();
+            } else {
+                ALOGE("*** %s read failed err=%d", __PRETTY_FUNCTION__, err);
+            }
+            return;
+        }
+
+        if (mIsSeeking) {
+            mIsSeeking = false;
+            notifyListener_l(MEDIA_SEEK_COMPLETE);
+        }
+
+        uint8_t* data = (static_cast<uint8_t*>(mediaBuffer->data()) +
+                mediaBuffer->range_offset());
+        ALOGV("*** %s got media buffer data=[%02hhx %02hhx %02hhx %02hhx]"
+              " offset=%d length=%d", __PRETTY_FUNCTION__,
+              data[0], data[1], data[2], data[3],
+              mediaBuffer->range_offset(), mediaBuffer->range_length());
+
+        int64_t mediaTimeUs;
+        CHECK(mediaBuffer->meta_data()->findInt64(kKeyTime, &mediaTimeUs));
+        ALOGV("*** timeUs=%lld", mediaTimeUs);
+
+        if (!mCurrentClockTransformValid) {
+            if (OK == mCCHelper.getCommonTime(&commonTimeNow)) {
+                mCurrentClockTransform.a_zero = mediaTimeUs;
+                mCurrentClockTransform.b_zero = commonTimeNow +
+                                                kAAHStartupLeadTimeUs;
+                mCurrentClockTransform.a_to_b_numer = 1;
+                mCurrentClockTransform.a_to_b_denom = mPlayRateIsPaused ? 0 : 1;
+                mCurrentClockTransformValid = true;
+            } else {
+                // Failed to get common time; either the service is down or
+                // common time is not synced.  Raise an error and shutdown the
+                // player.
+                ALOGE("*** Cannot begin transmission, unable to fetch common"
+                      " time. Dropping sample with pts=%lld", mediaTimeUs);
+                notifyListener_l(MEDIA_ERROR,
+                                 MEDIA_ERROR_UNKNOWN,
+                                 UNKNOWN_ERROR);
+                mPumpAudioEventPending = false;
+                break;
+            }
+        }
+
+        ALOGV("*** transmitting packet with pts=%lld", mediaTimeUs);
+
+        sp<TRTPAudioPacket> packet = new TRTPAudioPacket();
+        packet->setPTS(mediaTimeUs);
+        packet->setSubstreamID(1);
+
+        packet->setCodecType(TRTPAudioPacket::kCodecMPEG1Audio);
+        packet->setVolume(mTRTPVolume);
+        // TODO : introduce a throttle for this so we can control the
+        // frequency with which transforms get sent.
+        packet->setClockTransform(mCurrentClockTransform);
+        packet->setAccessUnitData(data, mediaBuffer->range_length());
+        packet->setRandomAccessPoint(true);
+
+        queuePacketToSender_l(packet);
+        mediaBuffer->release();
+
+        mLastQueuedMediaTimePTSValid = true;
+        mLastQueuedMediaTimePTS = mediaTimeUs;
+    }
+
+    { // Explicit scope for the autolock pattern.
+        Mutex::Autolock autoLock(mLock);
+
+        // If someone externally has cleared this flag, its because we should be
+        // shutting down.  Do not reschedule ourselves.
+        if (!mPumpAudioEventPending) {
+            return;
+        }
+
+        // Looks like no one canceled us explicitly.  Clear our flag and post a
+        // new event to ourselves.
+        mPumpAudioEventPending = false;
+        postPumpAudioEvent_l(10000);
+    }
+}
+
+void AAH_TXPlayer::queuePacketToSender_l(const sp<TRTPPacket>& packet) {
+    if (mAAH_Sender == NULL) {
+        return;
+    }
+
+    sp<AMessage> message = new AMessage(AAH_TXSender::kWhatSendPacket,
+                                        mAAH_Sender->handlerID());
+
+    {
+        Mutex::Autolock lock(mEndpointLock);
+        if (!mEndpointValid) {
+            return;
+        }
+
+        message->setInt32(AAH_TXSender::kSendPacketIPAddr, mEndpoint.addr);
+        message->setInt32(AAH_TXSender::kSendPacketPort, mEndpoint.port);
+    }
+
+    packet->setProgramID(mProgramID);
+    packet->setExpireTime(systemTime() + kAAHRetryKeepAroundTimeNs);
+    packet->pack();
+
+    message->setObject(AAH_TXSender::kSendPacketTRTPPacket, packet);
+
+    message->post();
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_tx_player.h b/media/libaah_rtp/aah_tx_player.h
new file mode 100644
index 0000000..64cf5dc1
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_player.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAH_TX_PLAYER_H__
+#define __AAH_TX_PLAYER_H__
+
+#include <common_time/cc_helper.h>
+#include <libstagefright/include/HTTPBase.h>
+#include <libstagefright/include/NuCachedSource2.h>
+#include <libstagefright/include/TimedEventQueue.h>
+#include <media/MediaPlayerInterface.h>
+#include <media/stagefright/MediaExtractor.h>
+#include <media/stagefright/MediaSource.h>
+#include <utils/LinearTransform.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+
+#include "aah_tx_sender.h"
+
+namespace android {
+
+class AAH_TXPlayer : public MediaPlayerHWInterface {
+  public:
+    AAH_TXPlayer();
+
+    virtual status_t    initCheck();
+    virtual status_t    setDataSource(const char *url,
+                                      const KeyedVector<String8, String8>*
+                                      headers);
+    virtual status_t    setDataSource(int fd, int64_t offset, int64_t length);
+    virtual status_t    setVideoSurface(const sp<Surface>& surface);
+    virtual status_t    setVideoSurfaceTexture(const sp<ISurfaceTexture>&
+                                               surfaceTexture);
+    virtual status_t    prepare();
+    virtual status_t    prepareAsync();
+    virtual status_t    start();
+    virtual status_t    stop();
+    virtual status_t    pause();
+    virtual bool        isPlaying();
+    virtual status_t    seekTo(int msec);
+    virtual status_t    getCurrentPosition(int *msec);
+    virtual status_t    getDuration(int *msec);
+    virtual status_t    reset();
+    virtual status_t    setLooping(int loop);
+    virtual player_type playerType();
+    virtual status_t    setParameter(int key, const Parcel &request);
+    virtual status_t    getParameter(int key, Parcel *reply);
+    virtual status_t    invoke(const Parcel& request, Parcel *reply);
+    virtual status_t    getMetadata(const media::Metadata::Filter& ids,
+                                    Parcel* records);
+    virtual status_t    setVolume(float leftVolume, float rightVolume);
+    virtual status_t    setAudioStreamType(audio_stream_type_t streamType);
+
+    // invoke method IDs
+    enum {
+        // set the IP address and port of the A@H receiver
+        kInvokeSetAAHDstIPPort = 1,
+
+        // set the destination IP address and port (and perhaps any additional
+        // parameters added in the future) packaged in one string
+        kInvokeSetAAHConfigBlob,
+    };
+
+    static const int64_t kAAHRetryKeepAroundTimeNs;
+
+  protected:
+    virtual ~AAH_TXPlayer();
+
+  private:
+    friend struct AwesomeEvent;
+
+    enum {
+        PLAYING             = 1,
+        PREPARING           = 8,
+        PREPARED            = 16,
+        PREPARE_CANCELLED   = 64,
+        CACHE_UNDERRUN      = 128,
+
+        // We are basically done preparing but are currently buffering
+        // sufficient data to begin playback and finish the preparation
+        // phase for good.
+        PREPARING_CONNECTED = 2048,
+
+        INCOGNITO           = 32768,
+    };
+
+    status_t setDataSource_l(const char *url,
+                             const KeyedVector<String8, String8> *headers);
+    status_t setDataSource_l(const sp<MediaExtractor>& extractor);
+    status_t finishSetDataSource_l();
+    status_t prepareAsync_l();
+    void onPrepareAsyncEvent();
+    void finishAsyncPrepare_l();
+    void abortPrepare(status_t err);
+    status_t play_l();
+    status_t pause_l(bool doClockUpdate = true);
+    status_t seekTo_l(int64_t timeUs);
+    void updateClockTransform_l(bool pause);
+    void sendEOS_l();
+    void cancelPlayerEvents(bool keepBufferingGoing = false);
+    void reset_l();
+    void notifyListener_l(int msg, int ext1 = 0, int ext2 = 0);
+    bool getBitrate_l(int64_t* bitrate);
+    status_t getDuration_l(int* msec);
+    bool getCachedDuration_l(int64_t* durationUs, bool* eos);
+    void ensureCacheIsFetching_l();
+    void postBufferingEvent_l();
+    void postPumpAudioEvent_l(int64_t delayUs);
+    void onBufferingUpdate();
+    void onPumpAudio();
+    void queuePacketToSender_l(const sp<TRTPPacket>& packet);
+
+    Mutex mLock;
+
+    TimedEventQueue mQueue;
+    bool mQueueStarted;
+
+    sp<TimedEventQueue::Event> mBufferingEvent;
+    bool mBufferingEventPending;
+
+    uint32_t mFlags;
+    uint32_t mExtractorFlags;
+
+    String8 mUri;
+    KeyedVector<String8, String8> mUriHeaders;
+
+    sp<DataSource> mFileSource;
+
+    sp<TimedEventQueue::Event> mAsyncPrepareEvent;
+    Condition mPreparedCondition;
+    status_t mPrepareResult;
+
+    bool mIsSeeking;
+    int64_t mSeekTimeUs;
+
+    sp<TimedEventQueue::Event> mPumpAudioEvent;
+    bool mPumpAudioEventPending;
+
+    sp<HTTPBase> mConnectingDataSource;
+    sp<NuCachedSource2> mCachedSource;
+
+    sp<MediaSource> mAudioSource;
+    int64_t mDurationUs;
+    int64_t mBitrate;
+
+    sp<AAH_TXSender> mAAH_Sender;
+    LinearTransform  mCurrentClockTransform;
+    bool             mCurrentClockTransformValid;
+    int64_t          mLastQueuedMediaTimePTS;
+    bool             mLastQueuedMediaTimePTSValid;
+    bool             mPlayRateIsPaused;
+    CCHelper         mCCHelper;
+
+    Mutex mEndpointLock;
+    AAH_TXSender::Endpoint mEndpoint;
+    bool mEndpointValid;
+    bool mEndpointRegistered;
+    uint16_t mProgramID;
+    uint8_t mTRTPVolume;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AAH_TXPlayer);
+};
+
+}  // namespace android
+
+#endif  // __AAH_TX_PLAYER_H__
diff --git a/media/libaah_rtp/aah_tx_sender.cpp b/media/libaah_rtp/aah_tx_sender.cpp
new file mode 100644
index 0000000..d991ea7
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_sender.cpp
@@ -0,0 +1,602 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <netinet/in.h>
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+#include <media/stagefright/foundation/AMessage.h>
+#include <utils/misc.h>
+
+#include "aah_tx_player.h"
+#include "aah_tx_sender.h"
+
+namespace android {
+
+const char* AAH_TXSender::kSendPacketIPAddr = "ipaddr";
+const char* AAH_TXSender::kSendPacketPort = "port";
+const char* AAH_TXSender::kSendPacketTRTPPacket = "trtp";
+
+const int AAH_TXSender::kRetryTrimIntervalUs = 100000;
+const int AAH_TXSender::kHeartbeatIntervalUs = 1000000;
+const int AAH_TXSender::kRetryBufferCapacity = 100;
+const nsecs_t AAH_TXSender::kHeartbeatTimeout = 600ull * 1000000000ull;
+
+Mutex AAH_TXSender::sLock;
+wp<AAH_TXSender> AAH_TXSender::sInstance;
+uint32_t AAH_TXSender::sNextEpoch;
+bool AAH_TXSender::sNextEpochValid = false;
+
+AAH_TXSender::AAH_TXSender() : mSocket(-1) {
+    mLastSentPacketTime = systemTime();
+}
+
+sp<AAH_TXSender> AAH_TXSender::GetInstance() {
+    Mutex::Autolock autoLock(sLock);
+
+    sp<AAH_TXSender> sender = sInstance.promote();
+
+    if (sender == NULL) {
+        sender = new AAH_TXSender();
+        if (sender == NULL) {
+            return NULL;
+        }
+
+        sender->mLooper = new ALooper();
+        if (sender->mLooper == NULL) {
+            return NULL;
+        }
+
+        sender->mReflector = new AHandlerReflector<AAH_TXSender>(sender.get());
+        if (sender->mReflector == NULL) {
+            return NULL;
+        }
+
+        sender->mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+        if (sender->mSocket == -1) {
+            ALOGW("%s unable to create socket", __PRETTY_FUNCTION__);
+            return NULL;
+        }
+
+        struct sockaddr_in bind_addr;
+        memset(&bind_addr, 0, sizeof(bind_addr));
+        bind_addr.sin_family = AF_INET;
+        if (bind(sender->mSocket,
+                 reinterpret_cast<const sockaddr*>(&bind_addr),
+                 sizeof(bind_addr)) < 0) {
+            ALOGW("%s unable to bind socket (errno %d)",
+                  __PRETTY_FUNCTION__, errno);
+            return NULL;
+        }
+
+        sender->mRetryReceiver = new RetryReceiver(sender.get());
+        if (sender->mRetryReceiver == NULL) {
+            return NULL;
+        }
+
+        sender->mLooper->setName("AAH_TXSender");
+        sender->mLooper->registerHandler(sender->mReflector);
+        sender->mLooper->start(false, false, PRIORITY_AUDIO);
+
+        if (sender->mRetryReceiver->run("AAH_TXSenderRetry", PRIORITY_AUDIO)
+                != OK) {
+            ALOGW("%s unable to start retry thread", __PRETTY_FUNCTION__);
+            return NULL;
+        }
+
+        sInstance = sender;
+    }
+
+    return sender;
+}
+
+AAH_TXSender::~AAH_TXSender() {
+    mLooper->stop();
+    mLooper->unregisterHandler(mReflector->id());
+
+    if (mRetryReceiver != NULL) {
+        mRetryReceiver->requestExit();
+        mRetryReceiver->mWakeupEvent.setEvent();
+        if (mRetryReceiver->requestExitAndWait() != OK) {
+            ALOGW("%s shutdown of retry receiver failed", __PRETTY_FUNCTION__);
+        }
+        mRetryReceiver->mSender = NULL;
+        mRetryReceiver.clear();
+    }
+
+    if (mSocket != -1) {
+        close(mSocket);
+    }
+}
+
+// Return the next epoch number usable for a newly instantiated endpoint.
+uint32_t AAH_TXSender::getNextEpoch() {
+    Mutex::Autolock autoLock(sLock);
+
+    if (sNextEpochValid) {
+        sNextEpoch = (sNextEpoch + 1) & TRTPPacket::kTRTPEpochMask;
+    } else {
+        sNextEpoch = ns2ms(systemTime()) & TRTPPacket::kTRTPEpochMask;
+        sNextEpochValid = true;
+    }
+
+    return sNextEpoch;
+}
+
+// Notify the sender that a player has started sending to this endpoint.
+// Returns a program ID for use by the calling player.
+uint16_t AAH_TXSender::registerEndpoint(const Endpoint& endpoint) {
+    Mutex::Autolock lock(mEndpointLock);
+
+    EndpointState* eps = mEndpointMap.valueFor(endpoint);
+    if (eps) {
+        eps->playerRefCount++;
+    } else {
+        eps = new EndpointState(getNextEpoch());
+        mEndpointMap.add(endpoint, eps);
+    }
+
+    // if this is the first registered endpoint, then send a message to start
+    // trimming retry buffers and a message to start sending heartbeats.
+    if (mEndpointMap.size() == 1) {
+        sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
+                                                handlerID());
+        trimMessage->post(kRetryTrimIntervalUs);
+
+        sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
+                                                     handlerID());
+        heartbeatMessage->post(kHeartbeatIntervalUs);
+    }
+
+    eps->nextProgramID++;
+    return eps->nextProgramID;
+}
+
+// Notify the sender that a player has ceased sending to this endpoint.
+// An endpoint's state can not be deleted until all of the endpoint's
+// registered players have called unregisterEndpoint.
+void AAH_TXSender::unregisterEndpoint(const Endpoint& endpoint) {
+    Mutex::Autolock lock(mEndpointLock);
+
+    EndpointState* eps = mEndpointMap.valueFor(endpoint);
+    if (eps) {
+        eps->playerRefCount--;
+        CHECK(eps->playerRefCount >= 0);
+    }
+}
+
+void AAH_TXSender::onMessageReceived(const sp<AMessage>& msg) {
+    switch (msg->what()) {
+        case kWhatSendPacket:
+            onSendPacket(msg);
+            break;
+
+        case kWhatTrimRetryBuffers:
+            trimRetryBuffers();
+            break;
+
+        case kWhatSendHeartbeats:
+            sendHeartbeats();
+            break;
+
+        default:
+            TRESPASS();
+            break;
+    }
+}
+
+void AAH_TXSender::onSendPacket(const sp<AMessage>& msg) {
+    sp<RefBase> obj;
+    CHECK(msg->findObject(kSendPacketTRTPPacket, &obj));
+    sp<TRTPPacket> packet = static_cast<TRTPPacket*>(obj.get());
+
+    uint32_t ipAddr;
+    CHECK(msg->findInt32(kSendPacketIPAddr,
+                         reinterpret_cast<int32_t*>(&ipAddr)));
+
+    int32_t port32;
+    CHECK(msg->findInt32(kSendPacketPort, &port32));
+    uint16_t port = port32;
+
+    Mutex::Autolock lock(mEndpointLock);
+    doSendPacket_l(packet, Endpoint(ipAddr, port));
+    mLastSentPacketTime = systemTime();
+}
+
+void AAH_TXSender::doSendPacket_l(const sp<TRTPPacket>& packet,
+                                  const Endpoint& endpoint) {
+    EndpointState* eps = mEndpointMap.valueFor(endpoint);
+    if (!eps) {
+        // the endpoint state has disappeared, so the player that sent this
+        // packet must be dead.
+        return;
+    }
+
+    // assign the packet's sequence number
+    packet->setEpoch(eps->epoch);
+    packet->setSeqNumber(eps->trtpSeqNumber++);
+
+    // add the packet to the retry buffer
+    RetryBuffer& retry = eps->retry;
+    retry.push_back(packet);
+
+    // send the packet
+    struct sockaddr_in addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = endpoint.addr;
+    addr.sin_port = htons(endpoint.port);
+
+    ssize_t result = sendto(mSocket,
+                            packet->getPacket(),
+                            packet->getPacketLen(),
+                            0,
+                            (const struct sockaddr *) &addr,
+                            sizeof(addr));
+    if (result == -1) {
+        ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+    }
+}
+
+void AAH_TXSender::trimRetryBuffers() {
+    Mutex::Autolock lock(mEndpointLock);
+
+    nsecs_t localTimeNow = systemTime();
+
+    Vector<Endpoint> endpointsToRemove;
+
+    for (size_t i = 0; i < mEndpointMap.size(); i++) {
+        EndpointState* eps = mEndpointMap.editValueAt(i);
+        RetryBuffer& retry = eps->retry;
+
+        while (!retry.isEmpty()) {
+            if (retry[0]->getExpireTime() < localTimeNow) {
+                retry.pop_front();
+            } else {
+                break;
+            }
+        }
+
+        if (retry.isEmpty() && eps->playerRefCount == 0) {
+            endpointsToRemove.add(mEndpointMap.keyAt(i));
+        }
+    }
+
+    // remove the state for any endpoints that are no longer in use
+    for (size_t i = 0; i < endpointsToRemove.size(); i++) {
+        Endpoint& e = endpointsToRemove.editItemAt(i);
+        ALOGD("*** %s removing endpoint addr=%08x", __PRETTY_FUNCTION__, e.addr);
+        size_t index = mEndpointMap.indexOfKey(e);
+        delete mEndpointMap.valueAt(index);
+        mEndpointMap.removeItemsAt(index);
+    }
+
+    // schedule the next trim
+    if (mEndpointMap.size()) {
+        sp<AMessage> trimMessage = new AMessage(kWhatTrimRetryBuffers,
+                                                handlerID());
+        trimMessage->post(kRetryTrimIntervalUs);
+    }
+}
+
+void AAH_TXSender::sendHeartbeats() {
+    Mutex::Autolock lock(mEndpointLock);
+
+    if (shouldSendHeartbeats_l()) {
+        for (size_t i = 0; i < mEndpointMap.size(); i++) {
+            EndpointState* eps = mEndpointMap.editValueAt(i);
+            const Endpoint& ep = mEndpointMap.keyAt(i);
+
+            sp<TRTPControlPacket> packet = new TRTPControlPacket();
+            packet->setCommandID(TRTPControlPacket::kCommandNop);
+
+            packet->setExpireTime(systemTime() +
+                                  AAH_TXPlayer::kAAHRetryKeepAroundTimeNs);
+            packet->pack();
+
+            doSendPacket_l(packet, ep);
+        }
+    }
+
+    // schedule the next heartbeat
+    if (mEndpointMap.size()) {
+        sp<AMessage> heartbeatMessage = new AMessage(kWhatSendHeartbeats,
+                                                     handlerID());
+        heartbeatMessage->post(kHeartbeatIntervalUs);
+    }
+}
+
+bool AAH_TXSender::shouldSendHeartbeats_l() {
+    // assert(holding endpoint lock)
+    return (systemTime() < (mLastSentPacketTime + kHeartbeatTimeout));
+}
+
+// Receiver
+
+// initial 4-byte ID of a retry request packet
+const uint32_t AAH_TXSender::RetryReceiver::kRetryRequestID = 'Treq';
+
+// initial 4-byte ID of a retry NAK packet
+const uint32_t AAH_TXSender::RetryReceiver::kRetryNakID = 'Tnak';
+
+// initial 4-byte ID of a fast start request packet
+const uint32_t AAH_TXSender::RetryReceiver::kFastStartRequestID = 'Tfst';
+
+AAH_TXSender::RetryReceiver::RetryReceiver(AAH_TXSender* sender)
+        : Thread(false),
+    mSender(sender) {}
+
+    AAH_TXSender::RetryReceiver::~RetryReceiver() {
+        mWakeupEvent.clearPendingEvents();
+    }
+
+// Returns true if val is within the interval bounded inclusively by
+// start and end.  Also handles the case where there is a rollover of the
+// range between start and end.
+template <typename T>
+static inline bool withinIntervalWithRollover(T val, T start, T end) {
+    return ((start <= end && val >= start && val <= end) ||
+            (start > end && (val >= start || val <= end)));
+}
+
+bool AAH_TXSender::RetryReceiver::threadLoop() {
+    struct pollfd pollFds[2];
+    pollFds[0].fd = mSender->mSocket;
+    pollFds[0].events = POLLIN;
+    pollFds[0].revents = 0;
+    pollFds[1].fd = mWakeupEvent.getWakeupHandle();
+    pollFds[1].events = POLLIN;
+    pollFds[1].revents = 0;
+
+    int pollResult = poll(pollFds, NELEM(pollFds), -1);
+    if (pollResult == -1) {
+        ALOGE("%s poll failed", __PRETTY_FUNCTION__);
+        return false;
+    }
+
+    if (exitPending()) {
+        ALOGI("*** %s exiting", __PRETTY_FUNCTION__);
+        return false;
+    }
+
+    if (pollFds[0].revents) {
+        handleRetryRequest();
+    }
+
+    return true;
+}
+
+void AAH_TXSender::RetryReceiver::handleRetryRequest() {
+    ALOGV("*** RX %s start", __PRETTY_FUNCTION__);
+
+    RetryPacket request;
+    struct sockaddr requestSrcAddr;
+    socklen_t requestSrcAddrLen = sizeof(requestSrcAddr);
+
+    ssize_t result = recvfrom(mSender->mSocket, &request, sizeof(request), 0,
+                              &requestSrcAddr, &requestSrcAddrLen);
+    if (result == -1) {
+        ALOGE("%s recvfrom failed, errno=%d", __PRETTY_FUNCTION__, errno);
+        return;
+    }
+
+    if (static_cast<size_t>(result) < sizeof(RetryPacket)) {
+        ALOGW("%s short packet received", __PRETTY_FUNCTION__);
+        return;
+    }
+
+    uint32_t host_request_id = ntohl(request.id);
+    if ((host_request_id != kRetryRequestID) &&
+        (host_request_id != kFastStartRequestID)) {
+        ALOGW("%s received retry request with bogus ID (%08x)",
+                __PRETTY_FUNCTION__, host_request_id);
+        return;
+    }
+
+    Endpoint endpoint(request.endpointIP, ntohs(request.endpointPort));
+
+    Mutex::Autolock lock(mSender->mEndpointLock);
+
+    EndpointState* eps = mSender->mEndpointMap.valueFor(endpoint);
+
+    if (eps == NULL || eps->retry.isEmpty()) {
+        // we have no retry buffer or an empty retry buffer for this endpoint,
+        // so NAK the entire request
+        RetryPacket nak = request;
+        nak.id = htonl(kRetryNakID);
+        result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+                        &requestSrcAddr, requestSrcAddrLen);
+        if (result == -1) {
+            ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+        }
+        return;
+    }
+
+    RetryBuffer& retry = eps->retry;
+
+    uint16_t startSeq = ntohs(request.seqStart);
+    uint16_t endSeq = ntohs(request.seqEnd);
+
+    uint16_t retryFirstSeq = retry[0]->getSeqNumber();
+    uint16_t retryLastSeq = retry[retry.size() - 1]->getSeqNumber();
+
+    // If this is a fast start, then force the start of the retry to match the
+    // start of the retransmit ring buffer (unless the end of the retransmit
+    // ring buffer is already past the point of fast start)
+    if ((host_request_id == kFastStartRequestID) &&
+        !((startSeq - retryFirstSeq) & 0x8000)) {
+        startSeq = retryFirstSeq;
+    }
+
+    int startIndex;
+    if (withinIntervalWithRollover(startSeq, retryFirstSeq, retryLastSeq)) {
+        startIndex = static_cast<uint16_t>(startSeq - retryFirstSeq);
+    } else {
+        startIndex = -1;
+    }
+
+    int endIndex;
+    if (withinIntervalWithRollover(endSeq, retryFirstSeq, retryLastSeq)) {
+        endIndex = static_cast<uint16_t>(endSeq - retryFirstSeq);
+    } else {
+        endIndex = -1;
+    }
+
+    if (startIndex == -1 && endIndex == -1) {
+        // no part of the request range is found in the retry buffer
+        RetryPacket nak = request;
+        nak.id = htonl(kRetryNakID);
+        result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+                        &requestSrcAddr, requestSrcAddrLen);
+        if (result == -1) {
+            ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+        }
+        return;
+    }
+
+    if (startIndex == -1) {
+        // NAK a subrange at the front of the request range
+        RetryPacket nak = request;
+        nak.id = htonl(kRetryNakID);
+        nak.seqEnd = htons(retryFirstSeq - 1);
+        result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+                        &requestSrcAddr, requestSrcAddrLen);
+        if (result == -1) {
+            ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+        }
+
+        startIndex = 0;
+    } else if (endIndex == -1) {
+        // NAK a subrange at the back of the request range
+        RetryPacket nak = request;
+        nak.id = htonl(kRetryNakID);
+        nak.seqStart = htons(retryLastSeq + 1);
+        result = sendto(mSender->mSocket, &nak, sizeof(nak), 0,
+                        &requestSrcAddr, requestSrcAddrLen);
+        if (result == -1) {
+            ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+        }
+
+        endIndex = retry.size() - 1;
+    }
+
+    // send the retry packets
+    for (int i = startIndex; i <= endIndex; i++) {
+        const sp<TRTPPacket>& replyPacket = retry[i];
+
+        result = sendto(mSender->mSocket,
+                        replyPacket->getPacket(),
+                        replyPacket->getPacketLen(),
+                        0,
+                        &requestSrcAddr,
+                        requestSrcAddrLen);
+
+        if (result == -1) {
+            ALOGW("%s sendto failed", __PRETTY_FUNCTION__);
+        }
+    }
+}
+
+// Endpoint
+
+AAH_TXSender::Endpoint::Endpoint()
+        : addr(0)
+        , port(0) { }
+
+AAH_TXSender::Endpoint::Endpoint(uint32_t a, uint16_t p)
+        : addr(a)
+        , port(p) {}
+
+bool AAH_TXSender::Endpoint::operator<(const Endpoint& other) const {
+    return ((addr < other.addr) ||
+            (addr == other.addr && port < other.port));
+}
+
+// EndpointState
+
+AAH_TXSender::EndpointState::EndpointState(uint32_t _epoch)
+    : retry(kRetryBufferCapacity)
+    , playerRefCount(1)
+    , trtpSeqNumber(0)
+    , nextProgramID(0)
+    , epoch(_epoch) { }
+
+// CircularBuffer
+
+template <typename T>
+CircularBuffer<T>::CircularBuffer(size_t capacity)
+        : mCapacity(capacity)
+        , mHead(0)
+        , mTail(0)
+        , mFillCount(0) {
+    mBuffer = new T[capacity];
+}
+
+template <typename T>
+CircularBuffer<T>::~CircularBuffer() {
+    delete [] mBuffer;
+}
+
+template <typename T>
+void CircularBuffer<T>::push_back(const T& item) {
+    if (this->isFull()) {
+        this->pop_front();
+    }
+    mBuffer[mHead] = item;
+    mHead = (mHead + 1) % mCapacity;
+    mFillCount++;
+}
+
+template <typename T>
+void CircularBuffer<T>::pop_front() {
+    CHECK(!isEmpty());
+    mBuffer[mTail] = T();
+    mTail = (mTail + 1) % mCapacity;
+    mFillCount--;
+}
+
+template <typename T>
+size_t CircularBuffer<T>::size() const {
+    return mFillCount;
+}
+
+template <typename T>
+bool CircularBuffer<T>::isFull() const {
+    return (mFillCount == mCapacity);
+}
+
+template <typename T>
+bool CircularBuffer<T>::isEmpty() const {
+    return (mFillCount == 0);
+}
+
+template <typename T>
+const T& CircularBuffer<T>::itemAt(size_t index) const {
+    CHECK(index < mFillCount);
+    return mBuffer[(mTail + index) % mCapacity];
+}
+
+template <typename T>
+const T& CircularBuffer<T>::operator[](size_t index) const {
+    return itemAt(index);
+}
+
+}  // namespace android
diff --git a/media/libaah_rtp/aah_tx_sender.h b/media/libaah_rtp/aah_tx_sender.h
new file mode 100644
index 0000000..74206c4
--- /dev/null
+++ b/media/libaah_rtp/aah_tx_sender.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __AAH_TX_SENDER_H__
+#define __AAH_TX_SENDER_H__
+
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AHandlerReflector.h>
+#include <utils/RefBase.h>
+#include <utils/threads.h>
+
+#include "aah_tx_packet.h"
+#include "pipe_event.h"
+
+namespace android {
+
+template <typename T> class CircularBuffer {
+  public:
+    CircularBuffer(size_t capacity);
+    ~CircularBuffer();
+    void push_back(const T& item);;
+    void pop_front();
+    size_t size() const;
+    bool isFull() const;
+    bool isEmpty() const;
+    const T& itemAt(size_t index) const;
+    const T& operator[](size_t index) const;
+
+  private:
+    T* mBuffer;
+    size_t mCapacity;
+    size_t mHead;
+    size_t mTail;
+    size_t mFillCount;
+
+    DISALLOW_EVIL_CONSTRUCTORS(CircularBuffer);
+};
+
+class AAH_TXSender : public virtual RefBase {
+  public:
+    ~AAH_TXSender();
+
+    static sp<AAH_TXSender> GetInstance();
+
+    ALooper::handler_id handlerID() { return mReflector->id(); }
+
+    // an IP address and port
+    struct Endpoint {
+        Endpoint();
+        Endpoint(uint32_t a, uint16_t p);
+        bool operator<(const Endpoint& other) const;
+
+        uint32_t addr;
+        uint16_t port;
+    };
+
+    uint16_t registerEndpoint(const Endpoint& endpoint);
+    void unregisterEndpoint(const Endpoint& endpoint);
+
+    enum {
+        kWhatSendPacket,
+        kWhatTrimRetryBuffers,
+        kWhatSendHeartbeats,
+    };
+
+    // fields for SendPacket messages
+    static const char* kSendPacketIPAddr;
+    static const char* kSendPacketPort;
+    static const char* kSendPacketTRTPPacket;
+
+  private:
+    AAH_TXSender();
+
+    static Mutex sLock;
+    static wp<AAH_TXSender> sInstance;
+    static uint32_t sNextEpoch;
+    static bool sNextEpochValid;
+
+    static uint32_t getNextEpoch();
+
+    typedef CircularBuffer<sp<TRTPPacket> > RetryBuffer;
+
+    // state maintained on a per-endpoint basis
+    struct EndpointState {
+        EndpointState(uint32_t epoch);
+        RetryBuffer retry;
+        int playerRefCount;
+        uint16_t trtpSeqNumber;
+        uint16_t nextProgramID;
+        uint32_t epoch;
+    };
+
+    friend class AHandlerReflector<AAH_TXSender>;
+    void onMessageReceived(const sp<AMessage>& msg);
+    void onSendPacket(const sp<AMessage>& msg);
+    void doSendPacket_l(const sp<TRTPPacket>& packet,
+                        const Endpoint& endpoint);
+    void trimRetryBuffers();
+    void sendHeartbeats();
+    bool shouldSendHeartbeats_l();
+
+    sp<ALooper> mLooper;
+    sp<AHandlerReflector<AAH_TXSender> > mReflector;
+
+    int mSocket;
+    nsecs_t mLastSentPacketTime;
+
+    DefaultKeyedVector<Endpoint, EndpointState*> mEndpointMap;
+    Mutex mEndpointLock;
+
+    static const int kRetryTrimIntervalUs;
+    static const int kHeartbeatIntervalUs;
+    static const int kRetryBufferCapacity;
+    static const nsecs_t kHeartbeatTimeout;
+
+    class RetryReceiver : public Thread {
+      private:
+        friend class AAH_TXSender;
+
+        RetryReceiver(AAH_TXSender* sender);
+        virtual ~RetryReceiver();
+        virtual bool threadLoop();
+        void handleRetryRequest();
+
+        static const int kMaxReceiverPacketLen;
+        static const uint32_t kRetryRequestID;
+        static const uint32_t kFastStartRequestID;
+        static const uint32_t kRetryNakID;
+
+        AAH_TXSender* mSender;
+        PipeEvent mWakeupEvent;
+    };
+
+    sp<RetryReceiver> mRetryReceiver;
+
+    DISALLOW_EVIL_CONSTRUCTORS(AAH_TXSender);
+};
+
+struct RetryPacket {
+    uint32_t id;
+    uint32_t endpointIP;
+    uint16_t endpointPort;
+    uint16_t seqStart;
+    uint16_t seqEnd;
+} __attribute__((packed));
+
+}  // namespace android
+
+#endif  // __AAH_TX_SENDER_H__
diff --git a/media/libaah_rtp/pipe_event.cpp b/media/libaah_rtp/pipe_event.cpp
new file mode 100644
index 0000000..b8e6960
--- /dev/null
+++ b/media/libaah_rtp/pipe_event.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LibAAH_RTP"
+#include <utils/Log.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "pipe_event.h"
+
+namespace android {
+
+PipeEvent::PipeEvent() {
+    pipe_[0] = -1;
+    pipe_[1] = -1;
+
+    // Create the pipe.
+    if (pipe(pipe_) >= 0) {
+        // Set non-blocking mode on the read side of the pipe so we can
+        // easily drain it whenever we wakeup.
+        fcntl(pipe_[0], F_SETFL, O_NONBLOCK);
+    } else {
+        ALOGE("Failed to create pipe event %d %d %d",
+              pipe_[0], pipe_[1], errno);
+        pipe_[0] = -1;
+        pipe_[1] = -1;
+    }
+}
+
+PipeEvent::~PipeEvent() {
+    if (pipe_[0] >= 0) {
+        close(pipe_[0]);
+    }
+
+    if (pipe_[1] >= 0) {
+        close(pipe_[1]);
+    }
+}
+
+void PipeEvent::clearPendingEvents() {
+    char drain_buffer[16];
+    while (read(pipe_[0], drain_buffer, sizeof(drain_buffer)) > 0) {
+        // No body.
+    }
+}
+
+bool PipeEvent::wait(int timeout) {
+    struct pollfd wait_fd;
+
+    wait_fd.fd = getWakeupHandle();
+    wait_fd.events = POLLIN;
+    wait_fd.revents = 0;
+
+    int res = poll(&wait_fd, 1, timeout);
+
+    if (res < 0) {
+        ALOGE("Wait error in PipeEvent; sleeping to prevent overload!");
+        usleep(1000);
+    }
+
+    return (res > 0);
+}
+
+void PipeEvent::setEvent() {
+    char foo = 'q';
+    write(pipe_[1], &foo, 1);
+}
+
+}  // namespace android
+
diff --git a/media/libaah_rtp/pipe_event.h b/media/libaah_rtp/pipe_event.h
new file mode 100644
index 0000000..e53b0fd
--- /dev/null
+++ b/media/libaah_rtp/pipe_event.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __PIPE_EVENT_H__
+#define __PIPE_EVENT_H__
+
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+class PipeEvent {
+  public:
+    PipeEvent();
+   ~PipeEvent();
+
+    bool initCheck() const {
+        return ((pipe_[0] >= 0) && (pipe_[1] >= 0));
+    }
+
+    int getWakeupHandle() const { return pipe_[0]; }
+
+    // block until the event fires; returns true if the event fired and false if
+    // the wait timed out.  Timeout is expressed in milliseconds; negative
+    // values mean wait forever.
+    bool wait(int timeout = -1);
+
+    void clearPendingEvents();
+    void setEvent();
+
+  private:
+    int pipe_[2];
+
+    DISALLOW_EVIL_CONSTRUCTORS(PipeEvent);
+};
+
+}  // namespace android
+
+#endif  // __PIPE_EVENT_H__
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index f9f997f..19b7e32 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -202,7 +202,7 @@
 status_t AudioEffect::setEnabled(bool enabled)
 {
     if (mStatus != NO_ERROR) {
-        return INVALID_OPERATION;
+        return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
     }
 
     status_t status = NO_ERROR;
@@ -231,7 +231,7 @@
 {
     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
         ALOGV("command() bad status %d", mStatus);
-        return INVALID_OPERATION;
+        return mStatus;
     }
 
     if (cmdCode == EFFECT_CMD_ENABLE || cmdCode == EFFECT_CMD_DISABLE) {
@@ -263,7 +263,7 @@
 status_t AudioEffect::setParameter(effect_param_t *param)
 {
     if (mStatus != NO_ERROR) {
-        return INVALID_OPERATION;
+        return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
     }
 
     if (param == NULL || param->psize == 0 || param->vsize == 0) {
@@ -281,7 +281,7 @@
 status_t AudioEffect::setParameterDeferred(effect_param_t *param)
 {
     if (mStatus != NO_ERROR) {
-        return INVALID_OPERATION;
+        return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
     }
 
     if (param == NULL || param->psize == 0 || param->vsize == 0) {
@@ -307,7 +307,7 @@
 status_t AudioEffect::setParameterCommit()
 {
     if (mStatus != NO_ERROR) {
-        return INVALID_OPERATION;
+        return (mStatus == ALREADY_EXISTS) ? INVALID_OPERATION : mStatus;
     }
 
     Mutex::Autolock _l(mCblk->lock);
@@ -321,7 +321,7 @@
 status_t AudioEffect::getParameter(effect_param_t *param)
 {
     if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
-        return INVALID_OPERATION;
+        return mStatus;
     }
 
     if (param == NULL || param->psize == 0 || param->vsize == 0) {
@@ -341,7 +341,7 @@
 void AudioEffect::binderDied()
 {
     ALOGW("IEffect died");
-    mStatus = NO_INIT;
+    mStatus = DEAD_OBJECT;
     if (mCbf != NULL) {
         status_t status = DEAD_OBJECT;
         mCbf(EVENT_ERROR, mUserData, &status);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index aead9a1..74c97ed 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -80,7 +80,9 @@
 
 AudioTrack::AudioTrack()
     : mStatus(NO_INIT),
-      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
+      mIsTimed(false),
+      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+      mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
 {
 }
 
@@ -96,7 +98,9 @@
         int notificationFrames,
         int sessionId)
     : mStatus(NO_INIT),
-      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
+      mIsTimed(false),
+      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+      mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             frameCount, flags, cbf, user, notificationFrames,
@@ -134,7 +138,9 @@
         int notificationFrames,
         int sessionId)
     : mStatus(NO_INIT),
-      mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
+      mIsTimed(false),
+      mPreviousPriority(ANDROID_PRIORITY_NORMAL),
+      mPreviousSchedulingGroup(ANDROID_TGROUP_DEFAULT)
 {
     mStatus = set(streamType, sampleRate, format, channelMask,
             0, flags, cbf, user, notificationFrames,
@@ -540,6 +546,10 @@
 {
     int afSamplingRate;
 
+    if (mIsTimed) {
+        return INVALID_OPERATION;
+    }
+
     if (AudioSystem::getOutputSamplingRate(&afSamplingRate, mStreamType) != NO_ERROR) {
         return NO_INIT;
     }
@@ -553,6 +563,10 @@
 
 uint32_t AudioTrack::getSampleRate() const
 {
+    if (mIsTimed) {
+        return INVALID_OPERATION;
+    }
+
     AutoMutex lock(mLock);
     return mCblk->sampleRate;
 }
@@ -578,6 +592,10 @@
         return NO_ERROR;
     }
 
+    if (mIsTimed) {
+        return INVALID_OPERATION;
+    }
+
     if (loopStart >= loopEnd ||
         loopEnd - loopStart > cblk->frameCount ||
         cblk->server > loopStart) {
@@ -641,6 +659,8 @@
 
 status_t AudioTrack::setPosition(uint32_t position)
 {
+    if (mIsTimed) return INVALID_OPERATION;
+
     AutoMutex lock(mLock);
 
     if (!stopped_l()) return INVALID_OPERATION;
@@ -791,6 +811,7 @@
                                                       ((uint16_t)flags) << 16,
                                                       sharedBuffer,
                                                       output,
+                                                      mIsTimed,
                                                       &mSessionId,
                                                       &status);
 
@@ -957,6 +978,7 @@
 {
 
     if (mSharedBuffer != 0) return INVALID_OPERATION;
+    if (mIsTimed) return INVALID_OPERATION;
 
     if (ssize_t(userSize) < 0) {
         // Sanity-check: user is most-likely passing an error code, and it would
@@ -1013,6 +1035,59 @@
 
 // -------------------------------------------------------------------------
 
+TimedAudioTrack::TimedAudioTrack() {
+    mIsTimed = true;
+}
+
+status_t TimedAudioTrack::allocateTimedBuffer(size_t size, sp<IMemory>* buffer)
+{
+    status_t result = UNKNOWN_ERROR;
+
+    // If the track is not invalid already, try to allocate a buffer.  alloc
+    // fails indicating that the server is dead, flag the track as invalid so
+    // we can attempt to restore in in just a bit.
+    if (!(mCblk->flags & CBLK_INVALID_MSK)) {
+        result = mAudioTrack->allocateTimedBuffer(size, buffer);
+        if (result == DEAD_OBJECT) {
+            android_atomic_or(CBLK_INVALID_ON, &mCblk->flags);
+        }
+    }
+
+    // If the track is invalid at this point, attempt to restore it. and try the
+    // allocation one more time.
+    if (mCblk->flags & CBLK_INVALID_MSK) {
+        mCblk->lock.lock();
+        result = restoreTrack_l(mCblk, false);
+        mCblk->lock.unlock();
+
+        if (result == OK)
+            result = mAudioTrack->allocateTimedBuffer(size, buffer);
+    }
+
+    return result;
+}
+
+status_t TimedAudioTrack::queueTimedBuffer(const sp<IMemory>& buffer,
+                                           int64_t pts)
+{
+    // restart track if it was disabled by audioflinger due to previous underrun
+    if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) {
+        android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags);
+        ALOGW("queueTimedBuffer() track %p disabled, restarting", this);
+        mAudioTrack->start(0);
+    }
+
+    return mAudioTrack->queueTimedBuffer(buffer, pts);
+}
+
+status_t TimedAudioTrack::setMediaTimeTransform(const LinearTransform& xform,
+                                                TargetTimeline target)
+{
+    return mAudioTrack->setMediaTimeTransform(xform, target);
+}
+
+// -------------------------------------------------------------------------
+
 bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread)
 {
     Buffer audioBuffer;
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 4507e5d..ebadbfa 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -90,6 +90,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
+                                bool isTimed,
                                 int *sessionId,
                                 status_t *status)
     {
@@ -105,6 +106,7 @@
         data.writeInt32(flags);
         data.writeStrongBinder(sharedBuffer->asBinder());
         data.writeInt32((int32_t) output);
+        data.writeInt32(isTimed);
         int lSessionId = 0;
         if (sessionId != NULL) {
             lSessionId = *sessionId;
@@ -689,11 +691,12 @@
             uint32_t flags = data.readInt32();
             sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
             audio_io_handle_t output = (audio_io_handle_t) data.readInt32();
+            bool isTimed = data.readInt32();
             int sessionId = data.readInt32();
             status_t status;
             sp<IAudioTrack> track = createTrack(pid,
                     (audio_stream_type_t) streamType, sampleRate, format,
-                    channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
+                    channelCount, bufferCount, flags, buffer, output, isTimed, &sessionId, &status);
             reply->writeInt32(sessionId);
             reply->writeInt32(status);
             reply->writeStrongBinder(track->asBinder());
diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp
index a7958de..28ebbbfc 100644
--- a/media/libmedia/IAudioTrack.cpp
+++ b/media/libmedia/IAudioTrack.cpp
@@ -35,7 +35,10 @@
     FLUSH,
     MUTE,
     PAUSE,
-    ATTACH_AUX_EFFECT
+    ATTACH_AUX_EFFECT,
+    ALLOCATE_TIMED_BUFFER,
+    QUEUE_TIMED_BUFFER,
+    SET_MEDIA_TIME_TRANSFORM,
 };
 
 class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -114,6 +117,52 @@
         }
         return status;
     }
+
+    virtual status_t allocateTimedBuffer(size_t size, sp<IMemory>* buffer) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeInt32(size);
+        status_t status = remote()->transact(ALLOCATE_TIMED_BUFFER,
+                                             data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+            if (status == NO_ERROR) {
+                *buffer = interface_cast<IMemory>(reply.readStrongBinder());
+            }
+        }
+        return status;
+    }
+
+    virtual status_t queueTimedBuffer(const sp<IMemory>& buffer,
+                                      int64_t pts) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeStrongBinder(buffer->asBinder());
+        data.writeInt64(pts);
+        status_t status = remote()->transact(QUEUE_TIMED_BUFFER,
+                                             data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        }
+        return status;
+    }
+
+    virtual status_t setMediaTimeTransform(const LinearTransform& xform,
+                                           int target) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
+        data.writeInt64(xform.a_zero);
+        data.writeInt64(xform.b_zero);
+        data.writeInt32(xform.a_to_b_numer);
+        data.writeInt32(xform.a_to_b_denom);
+        data.writeInt32(target);
+        status_t status = remote()->transact(SET_MEDIA_TIME_TRANSFORM,
+                                             data, &reply);
+        if (status == NO_ERROR) {
+            status = reply.readInt32();
+        }
+        return status;
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -159,10 +208,38 @@
             reply->writeInt32(attachAuxEffect(data.readInt32()));
             return NO_ERROR;
         } break;
+        case ALLOCATE_TIMED_BUFFER: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            sp<IMemory> buffer;
+            status_t status = allocateTimedBuffer(data.readInt32(), &buffer);
+            reply->writeInt32(status);
+            if (status == NO_ERROR) {
+                reply->writeStrongBinder(buffer->asBinder());
+            }
+            return NO_ERROR;
+        } break;
+        case QUEUE_TIMED_BUFFER: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            sp<IMemory> buffer = interface_cast<IMemory>(
+                data.readStrongBinder());
+            uint64_t pts = data.readInt64();
+            reply->writeInt32(queueTimedBuffer(buffer, pts));
+            return NO_ERROR;
+        } break;
+        case SET_MEDIA_TIME_TRANSFORM: {
+            CHECK_INTERFACE(IAudioTrack, data, reply);
+            LinearTransform xform;
+            xform.a_zero = data.readInt64();
+            xform.b_zero = data.readInt64();
+            xform.a_to_b_numer = data.readInt32();
+            xform.a_to_b_denom = data.readInt32();
+            int target = data.readInt32();
+            reply->writeInt32(setMediaTimeTransform(xform, target));
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
 }
 
 }; // namespace android
-
diff --git a/media/libmedia/IEffect.cpp b/media/libmedia/IEffect.cpp
index d469e28..5d40cc8 100644
--- a/media/libmedia/IEffect.cpp
+++ b/media/libmedia/IEffect.cpp
@@ -83,8 +83,15 @@
             size = *pReplySize;
         }
         data.writeInt32(size);
-        remote()->transact(COMMAND, data, &reply);
-        status_t status = reply.readInt32();
+
+        status_t status = remote()->transact(COMMAND, data, &reply);
+        if (status != NO_ERROR) {
+            if (pReplySize != NULL)
+                *pReplySize = 0;
+            return status;
+        }
+
+        status = reply.readInt32();
         size = reply.readInt32();
         if (size != 0 && pReplyData != NULL && pReplySize != NULL) {
             reply.read(pReplyData, size);
diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp
index 13b64e9..70f8c0c 100644
--- a/media/libmedia/Visualizer.cpp
+++ b/media/libmedia/Visualizer.cpp
@@ -168,7 +168,7 @@
         uint32_t replySize = mCaptureSize;
         status = command(VISUALIZER_CMD_CAPTURE, 0, NULL, &replySize, waveform);
         ALOGV("getWaveForm() command returned %d", status);
-        if (replySize == 0) {
+        if ((status == NO_ERROR) && (replySize == 0)) {
             status = NOT_ENOUGH_DATA;
         }
     } else {
diff --git a/media/libmediaplayerservice/Android.mk b/media/libmediaplayerservice/Android.mk
index a3e2517..e521648 100644
--- a/media/libmediaplayerservice/Android.mk
+++ b/media/libmediaplayerservice/Android.mk
@@ -29,7 +29,8 @@
 	libstagefright_omx    			\
 	libstagefright_foundation       \
 	libgui                          \
-	libdl
+	libdl                           \
+	libaah_rtp
 
 LOCAL_STATIC_LIBRARIES := \
         libstagefright_nuplayer                 \
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 4df7f3d..764eddc 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -70,6 +70,11 @@
 
 #include <OMX.h>
 
+namespace android {
+sp<MediaPlayerBase> createAAH_TXPlayer();
+sp<MediaPlayerBase> createAAH_RXPlayer();
+}
+
 namespace {
 using android::media::Metadata;
 using android::status_t;
@@ -593,6 +598,14 @@
         return NU_PLAYER;
     }
 
+    if (!strncasecmp("aahRX://", url, 8)) {
+        return AAH_RX_PLAYER;
+    }
+
+    if (!strncasecmp("aahTX://", url, 8)) {
+        return AAH_TX_PLAYER;
+    }
+
     // use MidiFile for MIDI extensions
     int lenURL = strlen(url);
     for (int i = 0; i < NELEM(FILE_EXTS); ++i) {
@@ -629,6 +642,14 @@
             ALOGV("Create Test Player stub");
             p = new TestPlayerStub();
             break;
+        case AAH_RX_PLAYER:
+            ALOGV(" create A@H RX Player");
+            p = createAAH_RXPlayer();
+            break;
+        case AAH_TX_PLAYER:
+            ALOGV(" create A@H TX Player");
+            p = createAAH_TXPlayer();
+            break;
         default:
             ALOGE("Unknown player type: %d", playerType);
             return NULL;
@@ -1031,9 +1052,21 @@
 status_t MediaPlayerService::Client::setVolume(float leftVolume, float rightVolume)
 {
     ALOGV("[%d] setVolume(%f, %f)", mConnId, leftVolume, rightVolume);
-    // TODO: for hardware output, call player instead
-    Mutex::Autolock l(mLock);
-    if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
+
+    // for hardware output, call player instead
+    sp<MediaPlayerBase> p = getPlayer();
+    {
+      Mutex::Autolock l(mLock);
+      if (p != 0 && p->hardwareOutput()) {
+          MediaPlayerHWInterface* hwp =
+                  reinterpret_cast<MediaPlayerHWInterface*>(p.get());
+          return hwp->setVolume(leftVolume, rightVolume);
+      } else {
+          if (mAudioOutput != 0) mAudioOutput->setVolume(leftVolume, rightVolume);
+          return NO_ERROR;
+      }
+    }
+
     return NO_ERROR;
 }
 
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 483e5ab..3f9ba47 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -93,13 +93,7 @@
 
 # The following was shamelessly copied from external/webkit/Android.mk and
 # currently must follow the same logic to determine how webkit was built and
-# if it's safe to link against libchromium.net
-
-# V8 also requires an ARMv7 CPU, and since we must use jsc, we cannot
-# use the Chrome http stack either.
-ifneq ($(strip $(ARCH_ARM_HAVE_ARMV7A)),true)
-  USE_ALT_HTTP := true
-endif
+# if it's safe to link against libchromium_net
 
 # See if the user has specified a stack they want to use
 HTTP_STACK = $(HTTP)
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index fef2a00..5b2ea1f 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -282,8 +282,6 @@
         mPrevSampleTimeUs = mStartTimeUs;
     }
 
-    int64_t timestampUs = mPrevSampleTimeUs;
-
     size_t numLostBytes = 0;
     if (mNumFramesReceived > 0) {  // Ignore earlier frame lost
         // getInputFramesLost() returns the number of lost frames.
@@ -293,37 +291,58 @@
 
     CHECK_EQ(numLostBytes & 1, 0u);
     CHECK_EQ(audioBuffer.size & 1, 0u);
-    size_t bufferSize = numLostBytes + audioBuffer.size;
-    MediaBuffer *buffer = new MediaBuffer(bufferSize);
     if (numLostBytes > 0) {
-        memset(buffer->data(), 0, numLostBytes);
-        memcpy((uint8_t *) buffer->data() + numLostBytes,
-                    audioBuffer.i16, audioBuffer.size);
-    } else {
-        if (audioBuffer.size == 0) {
-            ALOGW("Nothing is available from AudioRecord callback buffer");
-            buffer->release();
-            return OK;
-        }
-        memcpy((uint8_t *) buffer->data(),
-                audioBuffer.i16, audioBuffer.size);
+        // Loss of audio frames should happen rarely; thus the LOGW should
+        // not cause a logging spam
+        ALOGW("Lost audio record data: %d bytes", numLostBytes);
     }
 
+    while (numLostBytes > 0) {
+        size_t bufferSize = numLostBytes;
+        if (numLostBytes > kMaxBufferSize) {
+            numLostBytes -= kMaxBufferSize;
+            bufferSize = kMaxBufferSize;
+        } else {
+            numLostBytes = 0;
+        }
+        MediaBuffer *lostAudioBuffer = new MediaBuffer(bufferSize);
+        memset(lostAudioBuffer->data(), 0, bufferSize);
+        lostAudioBuffer->set_range(0, bufferSize);
+        queueInputBuffer_l(lostAudioBuffer, timeUs);
+    }
+
+    if (audioBuffer.size == 0) {
+        ALOGW("Nothing is available from AudioRecord callback buffer");
+        return OK;
+    }
+
+    const size_t bufferSize = audioBuffer.size;
+    MediaBuffer *buffer = new MediaBuffer(bufferSize);
+    memcpy((uint8_t *) buffer->data(),
+            audioBuffer.i16, audioBuffer.size);
     buffer->set_range(0, bufferSize);
-    timestampUs += ((1000000LL * (bufferSize >> 1)) +
-                    (mSampleRate >> 1)) / mSampleRate;
+    queueInputBuffer_l(buffer, timeUs);
+    return OK;
+}
+
+void AudioSource::queueInputBuffer_l(MediaBuffer *buffer, int64_t timeUs) {
+    const size_t bufferSize = buffer->range_length();
+    const size_t frameSize = mRecord->frameSize();
+    const int64_t timestampUs =
+                mPrevSampleTimeUs +
+                    ((1000000LL * (bufferSize / frameSize)) +
+                        (mSampleRate >> 1)) / mSampleRate;
 
     if (mNumFramesReceived == 0) {
         buffer->meta_data()->setInt64(kKeyAnchorTime, mStartTimeUs);
     }
+
     buffer->meta_data()->setInt64(kKeyTime, mPrevSampleTimeUs);
     buffer->meta_data()->setInt64(kKeyDriftTime, timeUs - mInitialReadTimeUs);
     mPrevSampleTimeUs = timestampUs;
-    mNumFramesReceived += buffer->range_length() / sizeof(int16_t);
+    mNumFramesReceived += bufferSize / frameSize;
     mBuffersReceived.push_back(buffer);
     mFrameAvailableCondition.signal();
-
-    return OK;
 }
 
 void AudioSource::trackMaxAmplitude(int16_t *data, int nSamples) {
diff --git a/native/android/Android.mk b/native/android/Android.mk
index 9940442..e2c99ee 100644
--- a/native/android/Android.mk
+++ b/native/android/Android.mk
@@ -18,6 +18,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
+    libandroidfw \
     libutils \
     libbinder \
     libui \
diff --git a/native/android/asset_manager.cpp b/native/android/asset_manager.cpp
index f5db57c..01db1d3 100644
--- a/native/android/asset_manager.cpp
+++ b/native/android/asset_manager.cpp
@@ -18,9 +18,9 @@
 #include <utils/Log.h>
 
 #include <android/asset_manager_jni.h>
-#include <utils/AssetManager.h>
-#include <utils/AssetDir.h>
-#include <utils/Asset.h>
+#include <androidfw/Asset.h>
+#include <androidfw/AssetDir.h>
+#include <androidfw/AssetManager.h>
 #include <utils/threads.h>
 
 #include "jni.h"
diff --git a/native/android/configuration.cpp b/native/android/configuration.cpp
index 687924b..7eb51dd 100644
--- a/native/android/configuration.cpp
+++ b/native/android/configuration.cpp
@@ -17,7 +17,7 @@
 #define LOG_TAG "Configuration"
 #include <utils/Log.h>
 
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
 
 #include <android_runtime/android_content_res_Configuration.h>
 
diff --git a/native/android/input.cpp b/native/android/input.cpp
index 91671c3..6eb2990 100644
--- a/native/android/input.cpp
+++ b/native/android/input.cpp
@@ -18,8 +18,8 @@
 #include <utils/Log.h>
 
 #include <android/input.h>
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
 #include <utils/Looper.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
diff --git a/native/android/obb.cpp b/native/android/obb.cpp
index e0cb1a6..e990024 100644
--- a/native/android/obb.cpp
+++ b/native/android/obb.cpp
@@ -18,8 +18,8 @@
 
 #include <android/obb.h>
 
+#include <androidfw/ObbFile.h>
 #include <utils/Log.h>
-#include <utils/ObbFile.h>
 
 using namespace android;
 
diff --git a/opengl/java/android/opengl/Group.java b/opengl/java/android/opengl/Group.java
deleted file mode 100644
index 1ef2953..0000000
--- a/opengl/java/android/opengl/Group.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.opengl;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.ShortBuffer;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Iterator;
-import javax.microedition.khronos.opengles.*;
-
-class MaterialIndices {
-
-    private Material material = null;
-    private ShortBuffer indexBuffer = null;
-
-    public MaterialIndices(Material material, ShortBuffer indexBuffer) {
-        this.material = material;
-        this.indexBuffer = indexBuffer;
-    }
-
-    public Material getMaterial() {
-        return material;
-    }
-
-    public ShortBuffer getIndexBuffer() {
-        return indexBuffer;
-    }
-}
-
-/**
- * {@hide}
- */
-public class Group {
-
-    private Object3D parent;
-    private String name;
-
-    private List<MaterialIndices> materialIndices =
-        new ArrayList<MaterialIndices>();
-
-    public Group(Object3D parent) {
-        this.parent = parent;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void load(DataInputStream dis) throws IOException {
-        dis.readInt(); // name length
-        this.name = dis.readUTF();
-
-        int numMaterials = dis.readInt();
-
-        for (int i = 0; i < numMaterials; i++) {
-            dis.readInt(); // material name length
-            String matName = dis.readUTF();
-            Material material = parent.getMaterial(matName);
-
-            int numIndices = dis.readInt();
-            byte[] indicesBytes = new byte[numIndices * 2];
-            dis.readFully(indicesBytes);
-
-            // Swap bytes from network to native order if necessary
-            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
-                int idx = 0;
-                for (int j = 0; j < numIndices; j++) {
-                    byte b0 = indicesBytes[idx];
-                    byte b1 = indicesBytes[idx + 1];
-                    indicesBytes[idx] = b1;
-                    indicesBytes[idx + 1] = b0;
-                    idx += 2;
-                }
-            }
-
-            ByteBuffer ibb = ByteBuffer.allocateDirect(2*numIndices);
-            ibb.order(ByteOrder.nativeOrder());
-            ibb.put(indicesBytes);
-            ibb.position(0);
-
-            ShortBuffer sb = ibb.asShortBuffer();
-            materialIndices.add(new MaterialIndices(material, sb));
-        }
-    }
-
-    public int getNumTriangles() {
-        int numTriangles = 0;
-        Iterator<MaterialIndices> iter = materialIndices.iterator();
-        while (iter.hasNext()) {
-            MaterialIndices matIdx = iter.next();
-            ShortBuffer indexBuffer = matIdx.getIndexBuffer();
-            numTriangles += indexBuffer.capacity()/3;
-        }
-        return numTriangles;
-    }
-
-    public void draw(GL10 gl) {
-        gl.glDisableClientState(gl.GL_COLOR_ARRAY);
-
-        gl.glVertexPointer(3, gl.GL_FIXED, 0, parent.getVertexBuffer());
-        gl.glEnableClientState(gl.GL_VERTEX_ARRAY);
-
-        gl.glNormalPointer(gl.GL_FIXED, 0, parent.getNormalBuffer());
-        gl.glEnableClientState(gl.GL_NORMAL_ARRAY);
-
-        if (parent.hasTexcoords()) {
-            gl.glTexCoordPointer(2, gl.GL_FIXED, 0, parent.getTexcoordBuffer());
-            gl.glEnableClientState(gl.GL_TEXTURE_COORD_ARRAY);
-            gl.glEnable(gl.GL_TEXTURE_2D);
-        } else {
-            gl.glDisable(gl.GL_TEXTURE_2D);
-        }
-
-        Iterator<MaterialIndices> iter = materialIndices.iterator();
-        while (iter.hasNext()) {
-            MaterialIndices matIdx = iter.next();
-            ShortBuffer indexBuffer = matIdx.getIndexBuffer();
-            Material mat = matIdx.getMaterial();
-            mat.setMaterialParameters(gl);
-            if (parent.hasTexcoords() && mat.getMap_Kd().length() > 0) {
-                Texture texture = parent.getTexture(mat.getMap_Kd());
-                texture.setTextureParameters(gl);
-            }
-
-            gl.glDrawElements(gl.GL_TRIANGLES,
-                    indexBuffer.capacity(),
-                    gl.GL_UNSIGNED_SHORT,
-                    indexBuffer);
-        }
-    }
-
-    public String toString() {
-        return "Group[" +
-        "name=" + name +
-        "]";
-    }
-}
diff --git a/opengl/java/android/opengl/Material.java b/opengl/java/android/opengl/Material.java
deleted file mode 100644
index 60a3e72..0000000
--- a/opengl/java/android/opengl/Material.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.opengl;
-
-import java.io.DataInputStream;
-import java.io.IOException;
-import javax.microedition.khronos.opengles.GL10;
-
-/**
- * {@hide}
- */
-public class Material {
-
-    private Object3D parent;
-    private String name;
-    private String map_kd;
-    private float[] ka = new float[4];
-    private float[] kd = new float[4];
-    private float[] ks = new float[4];
-    private float ns;
-    private int illum;
-    private float d;
-
-    private static float[] black = { 0.0f, 0.0f, 0.0f, 1.0f };
-
-    public Material(Object3D parent) {
-        this.parent = parent;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public String getMap_Kd() {
-        return map_kd;
-    }
-
-    public void setMaterialParameters(GL10 gl) {
-        gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0);
-        gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0);
-        gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0);
-        gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS,
-                Math.min(Math.max(ns, 0), 128));
-
-//      if (illum == 0) {
-//      gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, kd, 0);
-//      } else {
-//      gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_AMBIENT, ka, 0);
-//      gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_DIFFUSE, kd, 0);
-//      }
-
-//      if (illum > 1) {
-//      gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, ks, 0);
-//      gl.glMaterialf(gl.GL_FRONT_AND_BACK, gl.GL_SHININESS,
-//      Math.min(Math.max(ns, 0), 128));
-//      } else {
-//      gl.glMaterialfv(gl.GL_FRONT_AND_BACK, gl.GL_SPECULAR, black, 0);
-//      }
-    }
-
-    public void load(DataInputStream dis) throws IOException {
-        dis.readInt(); // name length
-        this.name = dis.readUTF();
-
-        dis.readInt(); // map_kdLength
-        this.map_kd = dis.readUTF();
-
-        if (parent.hasTexcoords() && map_kd.length() > 0) {
-            parent.loadTexture(map_kd);
-        }
-
-        this.ka[0] = dis.readFloat();
-        this.ka[1] = dis.readFloat();
-        this.ka[2] = dis.readFloat();
-        this.ka[3] = dis.readFloat();
-
-        this.kd[0] = dis.readFloat();
-        this.kd[1] = dis.readFloat();
-        this.kd[2] = dis.readFloat();
-        this.kd[3] = dis.readFloat();
-
-        this.ks[0] = dis.readFloat();
-        this.ks[1] = dis.readFloat();
-        this.ks[2] = dis.readFloat();
-        this.ks[3] = dis.readFloat();
-
-        this.ns = dis.readFloat();
-        this.illum = dis.readInt();
-        this.d = dis.readFloat();
-    }
-
-    public String toString() {
-        return "Material[" +
-        "name=\"" + name + "\"," +
-        "ka={" + ka[0] + "," + ka[1] + "," + ka[2] + "}," +
-        "kd={" + kd[0] + "," + kd[1] + "," + kd[2] + "}," +
-        "ks={" + ks[0] + "," + ks[1] + "," + ks[2] + "}," +
-        "ns=" + ns + "," +
-        "map_kd=\"" + 
-        (map_kd == null ? "" : map_kd) +
-        "\"," +
-        "illum=" + illum + "," +
-        "d=" + d +
-        "]";
-    }
-}
diff --git a/opengl/java/android/opengl/Object3D.java b/opengl/java/android/opengl/Object3D.java
deleted file mode 100644
index 340c6a7..0000000
--- a/opengl/java/android/opengl/Object3D.java
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.opengl;
-
-import java.io.BufferedReader;
-import java.io.DataInputStream;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.IntBuffer;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import javax.microedition.khronos.opengles.*;
-
-/**
- * {@hide}
- */
-public abstract class Object3D {
-
-    private boolean mHasTexcoords = false;
-
-    private float mBoundsMinX = Float.MAX_VALUE;
-    private float mBoundsMaxX = Float.MIN_VALUE;
-    private float mBoundsMinY = Float.MAX_VALUE;
-    private float mBoundsMaxY = Float.MIN_VALUE;
-    private float mBoundsMinZ = Float.MAX_VALUE;
-    private float mBoundsMaxZ = Float.MIN_VALUE;
-
-    private IntBuffer mVertexBuffer;
-    private IntBuffer mNormalBuffer;
-    private IntBuffer mTexcoordBuffer;
-
-    // All groups, by name
-    private Map<String, Group> mGroups;
-
-    // All materials, by name
-    private Map<String, Material> mMaterials;
-
-    // All texture maps, by name
-    private Map<String, Texture> mTextures;
-
-    public Object3D() {
-        reset();
-    }
-
-    /**
-     * Override this method with an implementation that contructs
-     * and InputStream from the given filename.  For example, if the
-     * source files are to be retrieved using an AssetManager,
-     * the implementation would use AssetManager.load() to
-     * get the input stream.
-     */
-    public abstract InputStream readFile(String filename) throws IOException;
-
-    private void reset() {
-        mVertexBuffer = mNormalBuffer = mTexcoordBuffer = null;
-
-        mGroups = new HashMap<String,Group>();
-        mMaterials = new HashMap<String,Material>();
-        mTextures = new HashMap<String,Texture>();
-    }
-
-    public Material getMaterial(String name) {
-        Material mat = mMaterials.get(name);
-        return mat;
-    }
-
-    public Texture getTexture(String name) {
-        return mTextures.get(name);
-    }
-
-    public IntBuffer getVertexBuffer() {
-        return mVertexBuffer;
-    }
-
-    public IntBuffer getNormalBuffer() {
-        return mNormalBuffer;
-    }
-
-    public IntBuffer getTexcoordBuffer() {
-        return mTexcoordBuffer;
-    }
-
-    public int getNumTriangles() {
-        int numTriangles = 0;
-        Iterator<Group> iter = mGroups.values().iterator();
-        while (iter.hasNext()) {
-            numTriangles += iter.next().getNumTriangles();
-        }
-        return numTriangles;
-    }
-
-    public boolean hasTexcoords() {
-        return mHasTexcoords;
-    }
-
-    public float getBoundsMinX() {
-        return mBoundsMinX;
-    }
-
-    public float getBoundsMaxX() {
-        return mBoundsMaxX;
-    }
-
-    public float getBoundsMinY() {
-        return mBoundsMinY;
-    }
-
-    public float getBoundsMaxY() {
-        return mBoundsMaxY;
-    }
-
-    public float getBoundsMinZ() {
-        return mBoundsMinZ;
-    }
-
-    public float getBoundsMaxZ() {
-        return mBoundsMaxZ;
-    }
-
-    public void loadTexture(String name) throws IOException {
-        InputStream is = readFile(name + ".raw");
-        Texture texture = new Texture(is);
-        mTextures.put(name, texture);
-    }
-
-    private static void verifyByte(DataInputStream dis, int b) 
-    throws IOException {
-        int x = dis.read() & 0xff;
-        if (x != b) {
-            throw new RuntimeException("Bad byte: " +
-                    x +
-                    " (expected " + b + ")");
-        }
-    }
-
-    public void load(String filename) throws IOException {
-        reset();
-
-        DataInputStream dis = new DataInputStream(readFile(filename));
-        verifyByte(dis, 'g' + 128);
-        verifyByte(dis, 'l');
-        verifyByte(dis, 'e');
-        verifyByte(dis, 's');
-
-        int numTuples = dis.readInt();
-
-        this.mBoundsMinX = dis.readFloat();
-        this.mBoundsMaxX = dis.readFloat();
-        this.mBoundsMinY = dis.readFloat();
-        this.mBoundsMaxY = dis.readFloat();
-        this.mBoundsMinZ = dis.readFloat();
-        this.mBoundsMaxZ = dis.readFloat();
-
-        this.mHasTexcoords = dis.readInt() == 1;
-
-        int intsPerTuple = mHasTexcoords ? 8 : 6;
-        int numInts = numTuples*intsPerTuple;
-
-        int len = 4*numTuples*(mHasTexcoords ? 8 : 6);
-
-        byte[] tmp = new byte[len];
-        int tidx = 0;
-        while (tidx < len) {
-            tidx += dis.read(tmp, tidx, len - tidx);
-        }
-        if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
-            for (int i = 0; i < len; i += 4) {
-                byte tmp0 = tmp[i];
-                byte tmp1 = tmp[i + 1];
-                byte tmp2 = tmp[i + 2];
-                byte tmp3 = tmp[i + 3];
-                tmp[i] = tmp3;
-                tmp[i + 1] = tmp2;
-                tmp[i + 2] = tmp1;
-                tmp[i + 3] = tmp0;
-            }
-        }
-
-        ByteBuffer allbb = ByteBuffer.allocateDirect(len);
-        allbb.order(ByteOrder.nativeOrder());
-        allbb.put(tmp);
-
-        allbb.position(0);
-        allbb.limit(4*3*numTuples);
-        ByteBuffer vbb = allbb.slice();
-        this.mVertexBuffer = vbb.asIntBuffer();
-        mVertexBuffer.position(0);
-
-        if (mHasTexcoords) {
-            allbb.position(allbb.limit());
-            allbb.limit(allbb.position() + 4*2*numTuples);
-            ByteBuffer tbb = allbb.slice();
-            this.mTexcoordBuffer = tbb.asIntBuffer();
-            mTexcoordBuffer.position(0);
-        }
-
-        allbb.position(allbb.limit());
-        allbb.limit(allbb.position() + 4*3*numTuples);
-        ByteBuffer nbb = allbb.slice();
-        this.mNormalBuffer = nbb.asIntBuffer();
-        mNormalBuffer.position(0);
-
-        int numMaterials = dis.readInt();
-        for (int i = 0; i < numMaterials; i++) {
-            Material mat = new Material(this);
-            mat.load(dis);
-            mMaterials.put(mat.getName(), mat);
-        }
-
-        int numGroups = dis.readInt();
-        for (int i = 0; i < numGroups; i++) {
-            Group g = new Group(this);
-            g.load(dis);
-            mGroups.put(g.getName(), g);
-        }
-    }
-
-    public void draw(GL10 gl) {
-        Iterator<Group> iter = mGroups.values().iterator();
-        while (iter.hasNext()) {
-            iter.next().draw(gl);
-        }
-    }
-}
-
diff --git a/opengl/java/android/opengl/Texture.java b/opengl/java/android/opengl/Texture.java
deleted file mode 100644
index dcd894d..0000000
--- a/opengl/java/android/opengl/Texture.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.opengl;
-
-import java.io.InputStream;
-import java.io.IOException;
-import java.nio.Buffer;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import javax.microedition.khronos.opengles.GL10;
-
-import android.content.res.AssetManager;
-
-/**
- * {@hide}
- */
-public class Texture {
-
-    private int width, height, bpp;
-    private ByteBuffer data;
-    private int name = -1;
-
-    // Texture maps have the following format.  All integers
-    // are 16 bits, high byte first.  Pixels are in 5/6/5
-    // RGB format, low byte first.
-    //
-    // width
-    // height
-    // pixel (0, 0)
-    // pixel (1, 0)
-    // ...
-    // pixel (width - 1, height - 1)
-
-    private int readInt16(InputStream is) throws IOException {
-        return is.read() | (is.read() << 8);
-    }
-
-    public Texture(InputStream is) throws IOException {
-        this.width  = readInt16(is);
-        this.height  = readInt16(is);
-        this.bpp = 2;
-
-        int npixels = width*height;
-        int nbytes = npixels*bpp;
-        byte[] arr = new byte[nbytes];
-
-        int idx = 0;
-        while (idx < nbytes) {
-            int nread = is.read(arr, idx, nbytes - idx);
-            idx += nread;
-        }
-
-        if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
-            // Swap pairs of bytes on big-endian platforms
-            for (int i = 0; i < npixels; i++) {
-                int j = i*2;
-                int k = j + 1;
-
-                byte tmp = arr[j];
-                arr[j] = arr[k];
-                arr[k] = tmp;
-            }
-        }
-
-        this.data = ByteBuffer.allocateDirect(arr.length);
-        this.data.order(ByteOrder.nativeOrder());
-        data.put(arr);
-        data.position(0);
-    }
-
-    private int loadTexture(GL10 gl,
-            int textureUnit,
-            int minFilter, int magFilter,
-            int wrapS, int wrapT,
-            int mode,
-            int width, int height,
-            int dataType,
-            Buffer data) {
-        int[] texture = new int[1];
-        gl.glGenTextures(1, texture, 0);
-
-        gl.glEnable(gl.GL_TEXTURE_2D);
-        gl.glClientActiveTexture(textureUnit);
-        gl.glBindTexture(gl.GL_TEXTURE_2D, texture[0]);
-        gl.glTexParameterf(gl.GL_TEXTURE_2D,
-                gl.GL_TEXTURE_MIN_FILTER,
-                minFilter);
-        gl.glTexParameterf(gl.GL_TEXTURE_2D,
-                gl.GL_TEXTURE_MAG_FILTER,
-                magFilter);
-        gl.glTexParameterf(gl.GL_TEXTURE_2D,
-                gl.GL_TEXTURE_WRAP_S,
-                wrapS);
-        gl.glTexParameterf(gl.GL_TEXTURE_2D,
-                gl.GL_TEXTURE_WRAP_T,
-                wrapT);
-        gl.glTexEnvf(gl.GL_TEXTURE_ENV, gl.GL_TEXTURE_ENV_MODE, mode);
-
-        gl.glTexImage2D(gl.GL_TEXTURE_2D, 0, gl.GL_RGB,
-                width, height,
-                0, gl.GL_RGB, dataType,
-                data);
-
-        return texture[0];
-    }
-
-    public void setTextureParameters(GL10 gl) {
-        if (name < 0) {
-            name = loadTexture(gl,
-                    gl.GL_TEXTURE0,
-                    gl.GL_NEAREST, gl.GL_NEAREST,
-                    gl.GL_REPEAT, gl.GL_REPEAT,
-                    gl.GL_MODULATE,
-                    width, height,
-                    gl.GL_UNSIGNED_SHORT_5_6_5,
-                    data);
-        }
-
-        gl.glBindTexture(gl.GL_TEXTURE_2D, name);
-    }
-}
diff --git a/opengl/libs/GLES_trace/TODO.txt b/opengl/libs/GLES_trace/TODO.txt
deleted file mode 100644
index f5e6e95..0000000
--- a/opengl/libs/GLES_trace/TODO.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-TODO:
-    - Context - Currently, we don't do anything regarding the contexts that are created.
-    Need to maintain more state regarding contexts, and figure out what happens in the
-    presence of multiple contexts.
-
-    - Transport: Each GLMessage is sent via a socket as soon as the message is received.
-    i.e., there is no buffering of messages. Buffering should improve performance.
-
-    - Initialization: On first connection, send some basic information that includes:
-        1. version of the trace library
-        2. implementation dependent GL state variables such as # of vertex arrays etc.
-
-    - eglSwapBuffers: The images are lzf compressed, but there is no mode that transfers
-    only the differences from the previous images.
diff --git a/opengl/libs/GLES_trace/gltrace.proto b/opengl/libs/GLES_trace/gltrace.proto
index 11cf24f..2893e6e 100644
--- a/opengl/libs/GLES_trace/gltrace.proto
+++ b/opengl/libs/GLES_trace/gltrace.proto
@@ -543,11 +543,13 @@
 
     required int32      context_id = 1;                     // GL context ID
     required int64      start_time = 2;                     // time when call was invoked
-    required int32      duration = 3;                       // duration of the call
+    required int32      duration = 3;                       // duration of the call (MONOTONIC TIME)
 
     required Function   function = 4 [default = invalid];   // GL function called
     repeated DataType   args = 5;                           // GL function's arguments
     optional DataType   returnValue = 6;                    // GL function's return value
 
     optional FrameBuffer fb = 7;                            // contents of the framebuffer
+
+    optional int32      threadtime = 8;                     // duration of the call (THREAD TIME)
 };
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.cpp b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
index bb9d4a7..d5f8180 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.cpp
@@ -1663,6 +1663,7 @@
 const int GLMessage::kArgsFieldNumber;
 const int GLMessage::kReturnValueFieldNumber;
 const int GLMessage::kFbFieldNumber;
+const int GLMessage::kThreadtimeFieldNumber;
 #endif  // !_MSC_VER
 
 GLMessage::GLMessage()
@@ -1689,6 +1690,7 @@
   function_ = 3000;
   returnvalue_ = NULL;
   fb_ = NULL;
+  threadtime_ = 0;
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
 }
 
@@ -1730,6 +1732,7 @@
     if (_has_bit(6)) {
       if (fb_ != NULL) fb_->::android::gltrace::GLMessage_FrameBuffer::Clear();
     }
+    threadtime_ = 0;
   }
   args_.Clear();
   ::memset(_has_bits_, 0, sizeof(_has_bits_));
@@ -1846,6 +1849,22 @@
         } else {
           goto handle_uninterpreted;
         }
+        if (input->ExpectTag(64)) goto parse_threadtime;
+        break;
+      }
+      
+      // optional int32 threadtime = 8;
+      case 8: {
+        if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==
+            ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) {
+         parse_threadtime:
+          DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<
+                   ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>(
+                 input, &threadtime_)));
+          _set_bit(7);
+        } else {
+          goto handle_uninterpreted;
+        }
         if (input->ExpectAtEnd()) return true;
         break;
       }
@@ -1906,6 +1925,11 @@
       7, this->fb(), output);
   }
   
+  // optional int32 threadtime = 8;
+  if (_has_bit(7)) {
+    ::google::protobuf::internal::WireFormatLite::WriteInt32(8, this->threadtime(), output);
+  }
+  
 }
 
 int GLMessage::ByteSize() const {
@@ -1953,6 +1977,13 @@
           this->fb());
     }
     
+    // optional int32 threadtime = 8;
+    if (has_threadtime()) {
+      total_size += 1 +
+        ::google::protobuf::internal::WireFormatLite::Int32Size(
+          this->threadtime());
+    }
+    
   }
   // repeated .android.gltrace.GLMessage.DataType args = 5;
   total_size += 1 * this->args_size();
@@ -1995,6 +2026,9 @@
     if (from._has_bit(6)) {
       mutable_fb()->::android::gltrace::GLMessage_FrameBuffer::MergeFrom(from.fb());
     }
+    if (from._has_bit(7)) {
+      set_threadtime(from.threadtime());
+    }
   }
 }
 
@@ -2028,6 +2062,7 @@
     args_.Swap(&other->args_);
     std::swap(returnvalue_, other->returnvalue_);
     std::swap(fb_, other->fb_);
+    std::swap(threadtime_, other->threadtime_);
     std::swap(_has_bits_[0], other->_has_bits_[0]);
     std::swap(_cached_size_, other->_cached_size_);
   }
diff --git a/opengl/libs/GLES_trace/src/gltrace.pb.h b/opengl/libs/GLES_trace/src/gltrace.pb.h
index e3b8990..a4fcbd3 100644
--- a/opengl/libs/GLES_trace/src/gltrace.pb.h
+++ b/opengl/libs/GLES_trace/src/gltrace.pb.h
@@ -1418,6 +1418,13 @@
   inline const ::android::gltrace::GLMessage_FrameBuffer& fb() const;
   inline ::android::gltrace::GLMessage_FrameBuffer* mutable_fb();
   
+  // optional int32 threadtime = 8;
+  inline bool has_threadtime() const;
+  inline void clear_threadtime();
+  static const int kThreadtimeFieldNumber = 8;
+  inline ::google::protobuf::int32 threadtime() const;
+  inline void set_threadtime(::google::protobuf::int32 value);
+  
   // @@protoc_insertion_point(class_scope:android.gltrace.GLMessage)
  private:
   mutable int _cached_size_;
@@ -1429,11 +1436,12 @@
   ::google::protobuf::RepeatedPtrField< ::android::gltrace::GLMessage_DataType > args_;
   ::android::gltrace::GLMessage_DataType* returnvalue_;
   ::android::gltrace::GLMessage_FrameBuffer* fb_;
+  ::google::protobuf::int32 threadtime_;
   friend void  protobuf_AddDesc_gltrace_2eproto();
   friend void protobuf_AssignDesc_gltrace_2eproto();
   friend void protobuf_ShutdownFile_gltrace_2eproto();
   
-  ::google::protobuf::uint32 _has_bits_[(7 + 31) / 32];
+  ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32];
   
   // WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
   inline bool _has_bit(int index) const {
@@ -1860,6 +1868,22 @@
   return fb_;
 }
 
+// optional int32 threadtime = 8;
+inline bool GLMessage::has_threadtime() const {
+  return _has_bit(7);
+}
+inline void GLMessage::clear_threadtime() {
+  threadtime_ = 0;
+  _clear_bit(7);
+}
+inline ::google::protobuf::int32 GLMessage::threadtime() const {
+  return threadtime_;
+}
+inline void GLMessage::set_threadtime(::google::protobuf::int32 value) {
+  _set_bit(7);
+  threadtime_ = value;
+}
+
 
 // @@protoc_insertion_point(namespace_scope)
 
diff --git a/opengl/libs/GLES_trace/src/gltrace_api.cpp b/opengl/libs/GLES_trace/src/gltrace_api.cpp
index a2366ac..358bf54 100644
--- a/opengl/libs/GLES_trace/src/gltrace_api.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_api.cpp
@@ -43,11 +43,15 @@
     arg_texture->add_intvalue((int)texture);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glActiveTexture(texture);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -70,11 +74,15 @@
     arg_shader->add_intvalue(shader);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glAttachShader(program, shader);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -103,11 +111,15 @@
     arg_name->add_intvalue((int)name);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindAttribLocation(program, index, name);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -130,11 +142,15 @@
     arg_buffer->add_intvalue(buffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindBuffer(target, buffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -157,11 +173,15 @@
     arg_framebuffer->add_intvalue(framebuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindFramebuffer(target, framebuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -184,11 +204,15 @@
     arg_renderbuffer->add_intvalue(renderbuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindRenderbuffer(target, renderbuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -211,11 +235,15 @@
     arg_texture->add_intvalue(texture);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindTexture(target, texture);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -250,11 +278,15 @@
     arg_alpha->add_floatvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendColor(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -271,11 +303,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendEquation(mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -298,11 +334,15 @@
     arg_modeAlpha->add_intvalue((int)modeAlpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendEquationSeparate(modeRGB, modeAlpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -325,11 +365,15 @@
     arg_dfactor->add_intvalue((int)dfactor);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendFunc(sfactor, dfactor);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -364,11 +408,15 @@
     arg_dstAlpha->add_intvalue((int)dstAlpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -403,11 +451,15 @@
     arg_usage->add_intvalue((int)usage);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBufferData(target, size, data, usage);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -442,11 +494,15 @@
     arg_data->add_intvalue((int)data);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBufferSubData(target, offset, size, data);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -463,9 +519,11 @@
     arg_target->add_intvalue((int)target);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLenum retValue = glContext->hooks->gl.glCheckFramebufferStatus(target);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -473,7 +531,9 @@
     rt->set_type(GLMessage::DataType::ENUM);
     rt->add_intvalue((int)retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -492,11 +552,15 @@
     arg_mask->add_intvalue(mask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClear(mask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -531,11 +595,15 @@
     arg_alpha->add_floatvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearColor(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -552,11 +620,15 @@
     arg_depth->add_floatvalue(depth);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearDepthf(depth);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -573,11 +645,15 @@
     arg_s->add_intvalue(s);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearStencil(s);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -612,11 +688,15 @@
     arg_alpha->add_boolvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glColorMask(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -633,11 +713,15 @@
     arg_shader->add_intvalue(shader);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCompileShader(shader);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -696,11 +780,15 @@
     arg_data->add_intvalue((int)data);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCompressedTexImage2D(target, level, internalformat, width, height, border, imageSize, data);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -765,11 +853,15 @@
     arg_data->add_intvalue((int)data);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -828,11 +920,15 @@
     arg_border->add_intvalue(border);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCopyTexImage2D(target, level, internalformat, x, y, width, height, border);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -891,11 +987,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCopyTexSubImage2D(target, level, xoffset, yoffset, x, y, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -906,9 +1006,11 @@
     glmsg.set_function(GLMessage::glCreateProgram);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLuint retValue = glContext->hooks->gl.glCreateProgram();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -916,7 +1018,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -935,9 +1039,11 @@
     arg_type->add_intvalue((int)type);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLuint retValue = glContext->hooks->gl.glCreateShader(type);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -945,7 +1051,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -964,11 +1072,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCullFace(mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -991,11 +1103,15 @@
     arg_buffers->add_intvalue((int)buffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteBuffers(n, buffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1018,11 +1134,15 @@
     arg_framebuffers->add_intvalue((int)framebuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteFramebuffers(n, framebuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1039,11 +1159,15 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteProgram(program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1066,11 +1190,15 @@
     arg_renderbuffers->add_intvalue((int)renderbuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteRenderbuffers(n, renderbuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1087,11 +1215,15 @@
     arg_shader->add_intvalue(shader);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteShader(shader);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1114,11 +1246,15 @@
     arg_textures->add_intvalue((int)textures);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteTextures(n, textures);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1135,11 +1271,15 @@
     arg_func->add_intvalue((int)func);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDepthFunc(func);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1156,11 +1296,15 @@
     arg_flag->add_boolvalue(flag);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDepthMask(flag);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1183,11 +1327,15 @@
     arg_zFar->add_floatvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDepthRangef(zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1210,11 +1358,15 @@
     arg_shader->add_intvalue(shader);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDetachShader(program, shader);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1231,11 +1383,15 @@
     arg_cap->add_intvalue((int)cap);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDisable(cap);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1252,11 +1408,15 @@
     arg_index->add_intvalue(index);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDisableVertexAttribArray(index);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1285,11 +1445,15 @@
     arg_count->add_intvalue(count);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawArrays(mode, first, count);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1324,11 +1488,15 @@
     arg_indices->add_intvalue((int)indices);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawElements(mode, count, type, indices);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1345,11 +1513,15 @@
     arg_cap->add_intvalue((int)cap);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEnable(cap);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1366,11 +1538,15 @@
     arg_index->add_intvalue(index);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEnableVertexAttribArray(index);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1381,11 +1557,15 @@
     glmsg.set_function(GLMessage::glFinish);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFinish();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1396,11 +1576,15 @@
     glmsg.set_function(GLMessage::glFlush);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFlush();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1435,11 +1619,15 @@
     arg_renderbuffer->add_intvalue(renderbuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1480,11 +1668,15 @@
     arg_level->add_intvalue(level);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFramebufferTexture2D(target, attachment, textarget, texture, level);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1501,11 +1693,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFrontFace(mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1528,11 +1724,15 @@
     arg_buffers->add_intvalue((int)buffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenBuffers(n, buffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1549,11 +1749,15 @@
     arg_target->add_intvalue((int)target);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenerateMipmap(target);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1576,11 +1780,15 @@
     arg_framebuffers->add_intvalue((int)framebuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenFramebuffers(n, framebuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1603,11 +1811,15 @@
     arg_renderbuffers->add_intvalue((int)renderbuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenRenderbuffers(n, renderbuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1630,11 +1842,15 @@
     arg_textures->add_intvalue((int)textures);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenTextures(n, textures);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1687,11 +1903,15 @@
     arg_name->add_intvalue((int)name);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetActiveAttrib(program, index, bufsize, length, size, type, name);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1744,11 +1964,15 @@
     arg_name->add_intvalue((int)name);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetActiveUniform(program, index, bufsize, length, size, type, name);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1783,11 +2007,15 @@
     arg_shaders->add_intvalue((int)shaders);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetAttachedShaders(program, maxcount, count, shaders);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1810,9 +2038,11 @@
     arg_name->add_intvalue((int)name);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     int retValue = glContext->hooks->gl.glGetAttribLocation(program, name);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -1820,7 +2050,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -1845,11 +2077,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetBooleanv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1878,11 +2114,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetBufferParameteriv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1893,9 +2133,11 @@
     glmsg.set_function(GLMessage::glGetError);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLenum retValue = glContext->hooks->gl.glGetError();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -1903,7 +2145,9 @@
     rt->set_type(GLMessage::DataType::ENUM);
     rt->add_intvalue((int)retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -1928,11 +2172,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetFloatv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1967,11 +2215,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetFramebufferAttachmentParameteriv(target, attachment, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -1994,11 +2246,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetIntegerv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2027,11 +2283,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetProgramiv(program, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2066,11 +2326,15 @@
     arg_infolog->add_intvalue((int)infolog);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetProgramInfoLog(program, bufsize, length, infolog);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2099,11 +2363,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetRenderbufferParameteriv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2132,11 +2400,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetShaderiv(shader, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2171,11 +2443,15 @@
     arg_infolog->add_intvalue((int)infolog);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetShaderInfoLog(shader, bufsize, length, infolog);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2210,11 +2486,15 @@
     arg_precision->add_intvalue((int)precision);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetShaderPrecisionFormat(shadertype, precisiontype, range, precision);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2249,11 +2529,15 @@
     arg_source->add_intvalue((int)source);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetShaderSource(shader, bufsize, length, source);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2270,9 +2554,11 @@
     arg_name->add_intvalue((int)name);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     const GLubyte* retValue = glContext->hooks->gl.glGetString(name);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2280,7 +2566,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue((int)retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2311,11 +2599,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexParameterfv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2344,11 +2636,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexParameteriv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2377,11 +2673,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetUniformfv(program, location, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2410,11 +2710,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetUniformiv(program, location, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2437,9 +2741,11 @@
     arg_name->add_intvalue((int)name);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     int retValue = glContext->hooks->gl.glGetUniformLocation(program, name);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2447,7 +2753,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2478,11 +2786,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetVertexAttribfv(index, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2511,11 +2823,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetVertexAttribiv(index, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2544,11 +2860,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetVertexAttribPointerv(index, pname, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2571,11 +2891,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glHint(target, mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2592,9 +2916,11 @@
     arg_buffer->add_intvalue(buffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsBuffer(buffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2602,7 +2928,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2621,9 +2949,11 @@
     arg_cap->add_intvalue((int)cap);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsEnabled(cap);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2631,7 +2961,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2650,9 +2982,11 @@
     arg_framebuffer->add_intvalue(framebuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsFramebuffer(framebuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2660,7 +2994,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2679,9 +3015,11 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsProgram(program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2689,7 +3027,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2708,9 +3048,11 @@
     arg_renderbuffer->add_intvalue(renderbuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsRenderbuffer(renderbuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2718,7 +3060,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2737,9 +3081,11 @@
     arg_shader->add_intvalue(shader);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsShader(shader);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2747,7 +3093,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2766,9 +3114,11 @@
     arg_texture->add_intvalue(texture);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsTexture(texture);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -2776,7 +3126,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -2795,11 +3147,15 @@
     arg_width->add_floatvalue(width);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLineWidth(width);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2816,11 +3172,15 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLinkProgram(program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2843,11 +3203,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPixelStorei(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2870,11 +3234,15 @@
     arg_units->add_floatvalue(units);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPolygonOffset(factor, units);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2927,11 +3295,15 @@
     arg_pixels->add_intvalue((int)pixels);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glReadPixels(x, y, width, height, format, type, pixels);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2942,11 +3314,15 @@
     glmsg.set_function(GLMessage::glReleaseShaderCompiler);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glReleaseShaderCompiler();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -2981,11 +3357,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRenderbufferStorage(target, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3008,11 +3388,15 @@
     arg_invert->add_boolvalue(invert);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glSampleCoverage(value, invert);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3047,11 +3431,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glScissor(x, y, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3092,11 +3480,15 @@
     arg_length->add_intvalue(length);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glShaderBinary(n, shaders, binaryformat, binary, length);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3131,11 +3523,15 @@
     arg_length->add_intvalue((int)length);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glShaderSource(shader, count, string, length);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3164,11 +3560,15 @@
     arg_mask->add_intvalue(mask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glStencilFunc(func, ref, mask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3203,11 +3603,15 @@
     arg_mask->add_intvalue(mask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glStencilFuncSeparate(face, func, ref, mask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3224,11 +3628,15 @@
     arg_mask->add_intvalue(mask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glStencilMask(mask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3251,11 +3659,15 @@
     arg_mask->add_intvalue(mask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glStencilMaskSeparate(face, mask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3284,11 +3696,15 @@
     arg_zpass->add_intvalue((int)zpass);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glStencilOp(fail, zfail, zpass);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3323,11 +3739,15 @@
     arg_zpass->add_intvalue((int)zpass);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glStencilOpSeparate(face, fail, zfail, zpass);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3392,11 +3812,15 @@
     arg_pixels->add_intvalue((int)pixels);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexImage2D(target, level, internalformat, width, height, border, format, type, pixels);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3425,11 +3849,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameterf(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3458,11 +3886,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameterfv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3491,11 +3923,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameteri(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3524,11 +3960,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameteriv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3593,11 +4033,15 @@
     arg_pixels->add_intvalue((int)pixels);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3620,11 +4064,15 @@
     arg_x->add_floatvalue(x);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform1f(location, x);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3653,11 +4101,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform1fv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3680,11 +4132,15 @@
     arg_x->add_intvalue(x);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform1i(location, x);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3713,11 +4169,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform1iv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3746,11 +4206,15 @@
     arg_y->add_floatvalue(y);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform2f(location, x, y);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3779,11 +4243,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform2fv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3812,11 +4280,15 @@
     arg_y->add_intvalue(y);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform2i(location, x, y);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3845,11 +4317,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform2iv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3884,11 +4360,15 @@
     arg_z->add_floatvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform3f(location, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3917,11 +4397,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform3fv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3956,11 +4440,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform3i(location, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -3989,11 +4477,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform3iv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4034,11 +4526,15 @@
     arg_w->add_floatvalue(w);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform4f(location, x, y, z, w);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4067,11 +4563,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform4fv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4112,11 +4612,15 @@
     arg_w->add_intvalue(w);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform4i(location, x, y, z, w);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4145,11 +4649,15 @@
     arg_v->add_intvalue((int)v);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniform4iv(location, count, v);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4184,11 +4692,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniformMatrix2fv(location, count, transpose, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4223,11 +4735,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniformMatrix3fv(location, count, transpose, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4262,11 +4778,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUniformMatrix4fv(location, count, transpose, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4283,11 +4803,15 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUseProgram(program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4304,11 +4828,15 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glValidateProgram(program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4331,11 +4859,15 @@
     arg_x->add_floatvalue(x);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib1f(indx, x);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4358,11 +4890,15 @@
     arg_values->add_intvalue((int)values);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib1fv(indx, values);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4391,11 +4927,15 @@
     arg_y->add_floatvalue(y);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib2f(indx, x, y);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4418,11 +4958,15 @@
     arg_values->add_intvalue((int)values);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib2fv(indx, values);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4457,11 +5001,15 @@
     arg_z->add_floatvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib3f(indx, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4484,11 +5032,15 @@
     arg_values->add_intvalue((int)values);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib3fv(indx, values);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4529,11 +5081,15 @@
     arg_w->add_floatvalue(w);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib4f(indx, x, y, z, w);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4556,11 +5112,15 @@
     arg_values->add_intvalue((int)values);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttrib4fv(indx, values);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4607,11 +5167,15 @@
     arg_ptr->add_intvalue((int)ptr);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexAttribPointer(indx, size, type, normalized, stride, ptr);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4646,11 +5210,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glViewport(x, y, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4676,11 +5244,15 @@
     arg_image->add_intvalue((int)image);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEGLImageTargetTexture2DOES(target, image);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4703,11 +5275,15 @@
     arg_image->add_intvalue((int)image);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEGLImageTargetRenderbufferStorageOES(target, image);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4748,11 +5324,15 @@
     arg_binary->add_intvalue((int)binary);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetProgramBinaryOES(program, bufSize, length, binaryFormat, binary);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4787,11 +5367,15 @@
     arg_length->add_intvalue(length);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramBinaryOES(program, binaryFormat, binary, length);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4814,9 +5398,11 @@
     arg_access->add_intvalue((int)access);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     void* retValue = glContext->hooks->gl.glMapBufferOES(target, access);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -4824,7 +5410,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue((int)retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -4843,9 +5431,11 @@
     arg_target->add_intvalue((int)target);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glUnmapBufferOES(target);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -4853,7 +5443,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -4884,11 +5476,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetBufferPointervOES(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -4959,11 +5555,15 @@
     arg_pixels->add_intvalue((int)pixels);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexImage3DOES(target, level, internalformat, width, height, depth, border, format, type, pixels);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5040,11 +5640,15 @@
     arg_pixels->add_intvalue((int)pixels);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5109,11 +5713,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCopyTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, x, y, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5178,11 +5786,15 @@
     arg_data->add_intvalue((int)data);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCompressedTexImage3DOES(target, level, internalformat, width, height, depth, border, imageSize, data);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5259,11 +5871,15 @@
     arg_data->add_intvalue((int)data);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCompressedTexSubImage3DOES(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5310,11 +5926,15 @@
     arg_zoffset->add_intvalue(zoffset);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFramebufferTexture3DOES(target, attachment, textarget, texture, level, zoffset);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5331,11 +5951,15 @@
     arg_array->add_intvalue(array);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindVertexArrayOES(array);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5358,11 +5982,15 @@
     arg_arrays->add_intvalue((int)arrays);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteVertexArraysOES(n, arrays);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5385,11 +6013,15 @@
     arg_arrays->add_intvalue((int)arrays);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenVertexArraysOES(n, arrays);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5406,9 +6038,11 @@
     arg_array->add_intvalue(array);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsVertexArrayOES(array);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -5416,7 +6050,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -5447,11 +6083,15 @@
     arg_groups->add_intvalue((int)groups);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetPerfMonitorGroupsAMD(numGroups, groupsSize, groups);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5492,11 +6132,15 @@
     arg_counters->add_intvalue((int)counters);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetPerfMonitorCountersAMD(group, numCounters, maxActiveCounters, counterSize, counters);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5531,11 +6175,15 @@
     arg_groupString->add_intvalue((int)groupString);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetPerfMonitorGroupStringAMD(group, bufSize, length, groupString);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5576,11 +6224,15 @@
     arg_counterString->add_intvalue((int)counterString);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetPerfMonitorCounterStringAMD(group, counter, bufSize, length, counterString);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5615,11 +6267,15 @@
     arg_data->add_intvalue((int)data);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetPerfMonitorCounterInfoAMD(group, counter, pname, data);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5642,11 +6298,15 @@
     arg_monitors->add_intvalue((int)monitors);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenPerfMonitorsAMD(n, monitors);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5669,11 +6329,15 @@
     arg_monitors->add_intvalue((int)monitors);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeletePerfMonitorsAMD(n, monitors);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5714,11 +6378,15 @@
     arg_countersList->add_intvalue((int)countersList);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glSelectPerfMonitorCountersAMD(monitor, enable, group, numCounters, countersList);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5735,11 +6403,15 @@
     arg_monitor->add_intvalue(monitor);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBeginPerfMonitorAMD(monitor);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5756,11 +6428,15 @@
     arg_monitor->add_intvalue(monitor);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEndPerfMonitorAMD(monitor);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5801,11 +6477,15 @@
     arg_bytesWritten->add_intvalue((int)bytesWritten);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetPerfMonitorCounterDataAMD(monitor, pname, dataSize, data, bytesWritten);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5876,11 +6556,15 @@
     arg_filter->add_intvalue((int)filter);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlitFramebufferANGLE(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5921,11 +6605,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRenderbufferStorageMultisampleANGLE(target, samples, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5966,11 +6654,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRenderbufferStorageMultisampleAPPLE(target, samples, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -5981,11 +6673,15 @@
     glmsg.set_function(GLMessage::glResolveMultisampleFramebufferAPPLE);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glResolveMultisampleFramebufferAPPLE();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6020,11 +6716,15 @@
     arg_label->add_intvalue((int)label);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLabelObjectEXT(type, object, length, label);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6065,11 +6765,15 @@
     arg_label->add_intvalue((int)label);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetObjectLabelEXT(type, object, bufSize, length, label);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6092,11 +6796,15 @@
     arg_marker->add_intvalue((int)marker);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glInsertEventMarkerEXT(length, marker);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6119,11 +6827,15 @@
     arg_marker->add_intvalue((int)marker);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPushGroupMarkerEXT(length, marker);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6134,11 +6846,15 @@
     glmsg.set_function(GLMessage::glPopGroupMarkerEXT);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPopGroupMarkerEXT();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6167,11 +6883,15 @@
     arg_attachments->add_intvalue((int)attachments);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDiscardFramebufferEXT(target, numAttachments, attachments);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6212,11 +6932,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRenderbufferStorageMultisampleEXT(target, samples, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6263,11 +6987,15 @@
     arg_samples->add_intvalue(samples);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFramebufferTexture2DMultisampleEXT(target, attachment, textarget, texture, level, samples);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6302,11 +7030,15 @@
     arg_primcount->add_intvalue(primcount);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultiDrawArraysEXT(mode, first, count, primcount);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6347,11 +7079,15 @@
     arg_primcount->add_intvalue(primcount);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultiDrawElementsEXT(mode, count, type, indices, primcount);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6374,11 +7110,15 @@
     arg_ids->add_intvalue((int)ids);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenQueriesEXT(n, ids);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6401,11 +7141,15 @@
     arg_ids->add_intvalue((int)ids);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteQueriesEXT(n, ids);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6422,9 +7166,11 @@
     arg_id->add_intvalue(id);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsQueryEXT(id);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6432,7 +7178,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -6457,11 +7205,15 @@
     arg_id->add_intvalue(id);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBeginQueryEXT(target, id);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6478,11 +7230,15 @@
     arg_target->add_intvalue((int)target);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEndQueryEXT(target);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6511,11 +7267,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetQueryivEXT(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6544,11 +7304,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetQueryObjectuivEXT(id, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6559,9 +7323,11 @@
     glmsg.set_function(GLMessage::glGetGraphicsResetStatusEXT);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLenum retValue = glContext->hooks->gl.glGetGraphicsResetStatusEXT();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6569,7 +7335,9 @@
     rt->set_type(GLMessage::DataType::ENUM);
     rt->add_intvalue((int)retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -6630,11 +7398,15 @@
     arg_data->add_intvalue((int)data);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glReadnPixelsEXT(x, y, width, height, format, type, bufSize, data);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6669,11 +7441,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetnUniformfvEXT(program, location, bufSize, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6708,11 +7484,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetnUniformivEXT(program, location, bufSize, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6741,11 +7521,15 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glUseProgramStagesEXT(pipeline, stages, program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6768,11 +7552,15 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glActiveShaderProgramEXT(pipeline, program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6801,9 +7589,11 @@
     arg_strings->add_intvalue((int)strings);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLuint retValue = glContext->hooks->gl.glCreateShaderProgramvEXT(type, count, strings);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6811,7 +7601,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -6830,11 +7622,15 @@
     arg_pipeline->add_intvalue(pipeline);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindProgramPipelineEXT(pipeline);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6857,11 +7653,15 @@
     arg_pipelines->add_intvalue((int)pipelines);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteProgramPipelinesEXT(n, pipelines);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6884,11 +7684,15 @@
     arg_pipelines->add_intvalue((int)pipelines);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenProgramPipelinesEXT(n, pipelines);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6905,9 +7709,11 @@
     arg_pipeline->add_intvalue(pipeline);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsProgramPipelineEXT(pipeline);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -6915,7 +7721,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -6946,11 +7754,15 @@
     arg_value->add_intvalue(value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramParameteriEXT(program, pname, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -6979,11 +7791,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetProgramPipelineivEXT(pipeline, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7012,11 +7828,15 @@
     arg_x->add_intvalue(x);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform1iEXT(program, location, x);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7051,11 +7871,15 @@
     arg_y->add_intvalue(y);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform2iEXT(program, location, x, y);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7096,11 +7920,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform3iEXT(program, location, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7147,11 +7975,15 @@
     arg_w->add_intvalue(w);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform4iEXT(program, location, x, y, z, w);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7180,11 +8012,15 @@
     arg_x->add_floatvalue(x);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform1fEXT(program, location, x);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7219,11 +8055,15 @@
     arg_y->add_floatvalue(y);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform2fEXT(program, location, x, y);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7264,11 +8104,15 @@
     arg_z->add_floatvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform3fEXT(program, location, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7315,11 +8159,15 @@
     arg_w->add_floatvalue(w);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform4fEXT(program, location, x, y, z, w);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7354,11 +8202,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform1ivEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7393,11 +8245,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform2ivEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7432,11 +8288,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform3ivEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7471,11 +8331,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform4ivEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7510,11 +8374,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform1fvEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7549,11 +8417,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform2fvEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7588,11 +8460,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform3fvEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7627,11 +8503,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniform4fvEXT(program, location, count, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7672,11 +8552,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniformMatrix2fvEXT(program, location, count, transpose, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7717,11 +8601,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniformMatrix3fvEXT(program, location, count, transpose, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7762,11 +8650,15 @@
     arg_value->add_intvalue((int)value);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glProgramUniformMatrix4fvEXT(program, location, count, transpose, value);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7783,11 +8675,15 @@
     arg_pipeline->add_intvalue(pipeline);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glValidateProgramPipelineEXT(pipeline);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7822,11 +8718,15 @@
     arg_infoLog->add_intvalue((int)infoLog);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetProgramPipelineInfoLogEXT(pipeline, bufSize, length, infoLog);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7861,11 +8761,15 @@
     arg_width->add_intvalue(width);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexStorage1DEXT(target, levels, internalformat, width);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7906,11 +8810,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexStorage2DEXT(target, levels, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -7957,11 +8865,15 @@
     arg_depth->add_intvalue(depth);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexStorage3DEXT(target, levels, internalformat, width, height, depth);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8002,11 +8914,15 @@
     arg_width->add_intvalue(width);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTextureStorage1DEXT(texture, target, levels, internalformat, width);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8053,11 +8969,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTextureStorage2DEXT(texture, target, levels, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8110,11 +9030,15 @@
     arg_depth->add_intvalue(depth);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTextureStorage3DEXT(texture, target, levels, internalformat, width, height, depth);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8155,11 +9079,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRenderbufferStorageMultisampleIMG(target, samples, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8206,11 +9134,15 @@
     arg_samples->add_intvalue(samples);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFramebufferTexture2DMultisampleIMG(target, attachment, textarget, texture, level, samples);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8227,11 +9159,15 @@
     arg_mask->add_boolvalue(mask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCoverageMaskNV(mask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8248,11 +9184,15 @@
     arg_operation->add_intvalue((int)operation);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCoverageOperationNV(operation);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8275,11 +9215,15 @@
     arg_bufs->add_intvalue((int)bufs);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawBuffersNV(n, bufs);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8302,11 +9246,15 @@
     arg_fences->add_intvalue((int)fences);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteFencesNV(n, fences);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8329,11 +9277,15 @@
     arg_fences->add_intvalue((int)fences);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenFencesNV(n, fences);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8350,9 +9302,11 @@
     arg_fence->add_intvalue(fence);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsFenceNV(fence);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -8360,7 +9314,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -8379,9 +9335,11 @@
     arg_fence->add_intvalue(fence);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glTestFenceNV(fence);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -8389,7 +9347,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -8420,11 +9380,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetFenceivNV(fence, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8441,11 +9405,15 @@
     arg_fence->add_intvalue(fence);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFinishFenceNV(fence);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8468,11 +9436,15 @@
     arg_condition->add_intvalue((int)condition);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glSetFenceNV(fence, condition);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8489,11 +9461,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glReadBufferNV(mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8516,11 +9492,15 @@
     arg_ref->add_floatvalue(ref);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glAlphaFuncQCOM(func, ref);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8549,11 +9529,15 @@
     arg_driverControls->add_intvalue((int)driverControls);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetDriverControlsQCOM(num, size, driverControls);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8588,11 +9572,15 @@
     arg_driverControlString->add_intvalue((int)driverControlString);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetDriverControlStringQCOM(driverControl, bufSize, length, driverControlString);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8609,11 +9597,15 @@
     arg_driverControl->add_intvalue(driverControl);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEnableDriverControlQCOM(driverControl);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8630,11 +9622,15 @@
     arg_driverControl->add_intvalue(driverControl);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDisableDriverControlQCOM(driverControl);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8663,11 +9659,15 @@
     arg_numTextures->add_intvalue((int)numTextures);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetTexturesQCOM(textures, maxTextures, numTextures);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8696,11 +9696,15 @@
     arg_numBuffers->add_intvalue((int)numBuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetBuffersQCOM(buffers, maxBuffers, numBuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8729,11 +9733,15 @@
     arg_numRenderbuffers->add_intvalue((int)numRenderbuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetRenderbuffersQCOM(renderbuffers, maxRenderbuffers, numRenderbuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8762,11 +9770,15 @@
     arg_numFramebuffers->add_intvalue((int)numFramebuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetFramebuffersQCOM(framebuffers, maxFramebuffers, numFramebuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8807,11 +9819,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetTexLevelParameterivQCOM(texture, face, level, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8840,11 +9856,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtTexObjectStateOverrideiQCOM(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8921,11 +9941,15 @@
     arg_texels->add_intvalue((int)texels);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetTexSubImageQCOM(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texels);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8948,11 +9972,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetBufferPointervQCOM(target, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -8981,11 +10009,15 @@
     arg_numShaders->add_intvalue((int)numShaders);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetShadersQCOM(shaders, maxShaders, numShaders);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9014,11 +10046,15 @@
     arg_numPrograms->add_intvalue((int)numPrograms);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetProgramsQCOM(programs, maxPrograms, numPrograms);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9035,9 +10071,11 @@
     arg_program->add_intvalue(program);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glExtIsProgramBinaryQCOM(program);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -9045,7 +10083,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -9082,11 +10122,15 @@
     arg_length->add_intvalue((int)length);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glExtGetProgramBinarySourceQCOM(program, shadertype, source, length);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9127,11 +10171,15 @@
     arg_preserveMask->add_intvalue(preserveMask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glStartTilingQCOM(x, y, width, height, preserveMask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9148,11 +10196,15 @@
     arg_preserveMask->add_intvalue(preserveMask);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEndTilingQCOM(preserveMask);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9178,11 +10230,15 @@
     arg_ref->add_floatvalue(ref);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glAlphaFunc(func, ref);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9205,11 +10261,15 @@
     arg_equation->add_intvalue((int)equation);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClipPlanef(plane, equation);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9244,11 +10304,15 @@
     arg_alpha->add_floatvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glColor4f(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9271,11 +10335,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFogf(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9298,11 +10366,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFogfv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9349,11 +10421,15 @@
     arg_zFar->add_floatvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFrustumf(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9376,11 +10452,15 @@
     arg_eqn->add_intvalue((int)eqn);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetClipPlanef(pname, eqn);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9409,11 +10489,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetLightfv(light, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9442,11 +10526,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetMaterialfv(face, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9475,11 +10563,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexEnvfv(env, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9502,11 +10594,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightModelf(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9529,11 +10625,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightModelfv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9562,11 +10662,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightf(light, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9595,11 +10699,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightfv(light, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9616,11 +10724,15 @@
     arg_m->add_intvalue((int)m);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLoadMatrixf(m);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9649,11 +10761,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMaterialf(face, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9682,11 +10798,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMaterialfv(face, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9703,11 +10823,15 @@
     arg_m->add_intvalue((int)m);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultMatrixf(m);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9748,11 +10872,15 @@
     arg_q->add_floatvalue(q);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultiTexCoord4f(target, s, t, r, q);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9781,11 +10909,15 @@
     arg_nz->add_floatvalue(nz);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glNormal3f(nx, ny, nz);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9832,11 +10964,15 @@
     arg_zFar->add_floatvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glOrthof(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9859,11 +10995,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointParameterf(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9886,11 +11026,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointParameterfv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9907,11 +11051,15 @@
     arg_size->add_floatvalue(size);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointSize(size);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9946,11 +11094,15 @@
     arg_z->add_floatvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRotatef(angle, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -9979,11 +11131,15 @@
     arg_z->add_floatvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glScalef(x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10012,11 +11168,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnvf(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10045,11 +11205,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnvfv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10078,11 +11242,15 @@
     arg_z->add_floatvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTranslatef(x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10105,11 +11273,15 @@
     arg_ref->add_intvalue(ref);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glAlphaFuncx(func, ref);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10144,11 +11316,15 @@
     arg_alpha->add_intvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearColorx(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10165,11 +11341,15 @@
     arg_depth->add_intvalue(depth);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearDepthx(depth);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10186,11 +11366,15 @@
     arg_texture->add_intvalue((int)texture);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClientActiveTexture(texture);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10213,11 +11397,15 @@
     arg_equation->add_intvalue((int)equation);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClipPlanex(plane, equation);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10252,11 +11440,15 @@
     arg_alpha->add_intvalue((int)alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glColor4ub(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10291,11 +11483,15 @@
     arg_alpha->add_intvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glColor4x(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10330,11 +11526,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glColorPointer(size, type, stride, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10357,11 +11557,15 @@
     arg_zFar->add_intvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDepthRangex(zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10378,11 +11582,15 @@
     arg_array->add_intvalue((int)array);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDisableClientState(array);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10399,11 +11607,15 @@
     arg_array->add_intvalue((int)array);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glEnableClientState(array);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10426,11 +11638,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFogx(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10453,11 +11669,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFogxv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10504,11 +11724,15 @@
     arg_zFar->add_intvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFrustumx(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10531,11 +11755,15 @@
     arg_eqn->add_intvalue((int)eqn);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetClipPlanex(pname, eqn);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10558,11 +11786,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetFixedv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10591,11 +11823,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetLightxv(light, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10624,11 +11860,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetMaterialxv(face, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10651,11 +11891,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetPointerv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10684,11 +11928,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexEnviv(env, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10717,11 +11965,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexEnvxv(env, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10750,11 +12002,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexParameterxv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10777,11 +12033,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightModelx(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10804,11 +12064,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightModelxv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10837,11 +12101,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightx(light, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10870,11 +12138,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightxv(light, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10891,11 +12163,15 @@
     arg_width->add_intvalue(width);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLineWidthx(width);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10906,11 +12182,15 @@
     glmsg.set_function(GLMessage::glLoadIdentity);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLoadIdentity();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10927,11 +12207,15 @@
     arg_m->add_intvalue((int)m);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLoadMatrixx(m);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10948,11 +12232,15 @@
     arg_opcode->add_intvalue((int)opcode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLogicOp(opcode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -10981,11 +12269,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMaterialx(face, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11014,11 +12306,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMaterialxv(face, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11035,11 +12331,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMatrixMode(mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11056,11 +12356,15 @@
     arg_m->add_intvalue((int)m);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultMatrixx(m);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11101,11 +12405,15 @@
     arg_q->add_intvalue(q);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultiTexCoord4x(target, s, t, r, q);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11134,11 +12442,15 @@
     arg_nz->add_intvalue(nz);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glNormal3x(nx, ny, nz);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11167,11 +12479,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glNormalPointer(type, stride, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11218,11 +12534,15 @@
     arg_zFar->add_intvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glOrthox(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11245,11 +12565,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointParameterx(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11272,11 +12596,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointParameterxv(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11293,11 +12621,15 @@
     arg_size->add_intvalue(size);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointSizex(size);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11320,11 +12652,15 @@
     arg_units->add_intvalue(units);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPolygonOffsetx(factor, units);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11335,11 +12671,15 @@
     glmsg.set_function(GLMessage::glPopMatrix);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPopMatrix();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11350,11 +12690,15 @@
     glmsg.set_function(GLMessage::glPushMatrix);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPushMatrix();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11389,11 +12733,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRotatex(angle, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11416,11 +12764,15 @@
     arg_invert->add_boolvalue(invert);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glSampleCoveragex(value, invert);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11449,11 +12801,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glScalex(x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11470,11 +12826,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glShadeModel(mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11509,11 +12869,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexCoordPointer(size, type, stride, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11542,11 +12906,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnvi(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11575,11 +12943,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnvx(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11608,11 +12980,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnviv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11641,11 +13017,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnvxv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11674,11 +13054,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameterx(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11707,11 +13091,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameterxv(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11740,11 +13128,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTranslatex(x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11779,11 +13171,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glVertexPointer(size, type, stride, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11812,11 +13208,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointSizePointerOES(type, stride, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11842,11 +13242,15 @@
     arg_modeAlpha->add_intvalue((int)modeAlpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendEquationSeparateOES(modeRGB, modeAlpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11881,11 +13285,15 @@
     arg_dstAlpha->add_intvalue((int)dstAlpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendFuncSeparateOES(srcRGB, dstRGB, srcAlpha, dstAlpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11902,11 +13310,15 @@
     arg_mode->add_intvalue((int)mode);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBlendEquationOES(mode);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11947,11 +13359,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexsOES(x, y, z, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -11992,11 +13408,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexiOES(x, y, z, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12037,11 +13457,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexxOES(x, y, z, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12058,11 +13482,15 @@
     arg_coords->add_intvalue((int)coords);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexsvOES(coords);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12079,11 +13507,15 @@
     arg_coords->add_intvalue((int)coords);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexivOES(coords);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12100,11 +13532,15 @@
     arg_coords->add_intvalue((int)coords);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexxvOES(coords);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12145,11 +13581,15 @@
     arg_height->add_floatvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexfOES(x, y, z, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12166,11 +13606,15 @@
     arg_coords->add_intvalue((int)coords);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDrawTexfvOES(coords);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12193,11 +13637,15 @@
     arg_ref->add_intvalue(ref);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glAlphaFuncxOES(func, ref);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12232,11 +13680,15 @@
     arg_alpha->add_intvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearColorxOES(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12253,11 +13705,15 @@
     arg_depth->add_intvalue(depth);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearDepthxOES(depth);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12280,11 +13736,15 @@
     arg_equation->add_intvalue((int)equation);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClipPlanexOES(plane, equation);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12319,11 +13779,15 @@
     arg_alpha->add_intvalue(alpha);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glColor4xOES(red, green, blue, alpha);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12346,11 +13810,15 @@
     arg_zFar->add_intvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDepthRangexOES(zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12373,11 +13841,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFogxOES(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12400,11 +13872,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFogxvOES(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12451,11 +13927,15 @@
     arg_zFar->add_intvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFrustumxOES(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12478,11 +13958,15 @@
     arg_eqn->add_intvalue((int)eqn);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetClipPlanexOES(pname, eqn);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12505,11 +13989,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetFixedvOES(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12538,11 +14026,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetLightxvOES(light, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12571,11 +14063,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetMaterialxvOES(face, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12604,11 +14100,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexEnvxvOES(env, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12637,11 +14137,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexParameterxvOES(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12664,11 +14168,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightModelxOES(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12691,11 +14199,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightModelxvOES(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12724,11 +14236,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightxOES(light, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12757,11 +14273,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLightxvOES(light, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12778,11 +14298,15 @@
     arg_width->add_intvalue(width);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLineWidthxOES(width);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12799,11 +14323,15 @@
     arg_m->add_intvalue((int)m);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLoadMatrixxOES(m);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12832,11 +14360,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMaterialxOES(face, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12865,11 +14397,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMaterialxvOES(face, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12886,11 +14422,15 @@
     arg_m->add_intvalue((int)m);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultMatrixxOES(m);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12931,11 +14471,15 @@
     arg_q->add_intvalue(q);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMultiTexCoord4xOES(target, s, t, r, q);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -12964,11 +14508,15 @@
     arg_nz->add_intvalue(nz);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glNormal3xOES(nx, ny, nz);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13015,11 +14563,15 @@
     arg_zFar->add_intvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glOrthoxOES(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13042,11 +14594,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointParameterxOES(pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13069,11 +14625,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointParameterxvOES(pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13090,11 +14650,15 @@
     arg_size->add_intvalue(size);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPointSizexOES(size);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13117,11 +14681,15 @@
     arg_units->add_intvalue(units);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glPolygonOffsetxOES(factor, units);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13156,11 +14724,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRotatexOES(angle, x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13183,11 +14755,15 @@
     arg_invert->add_boolvalue(invert);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glSampleCoveragexOES(value, invert);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13216,11 +14792,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glScalexOES(x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13249,11 +14829,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnvxOES(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13282,11 +14866,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexEnvxvOES(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13315,11 +14903,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameterxOES(target, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13348,11 +14940,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexParameterxvOES(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13381,11 +14977,15 @@
     arg_z->add_intvalue(z);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTranslatexOES(x, y, z);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13402,9 +15002,11 @@
     arg_renderbuffer->add_intvalue(renderbuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsRenderbufferOES(renderbuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13412,7 +15014,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -13437,11 +15041,15 @@
     arg_renderbuffer->add_intvalue(renderbuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindRenderbufferOES(target, renderbuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13464,11 +15072,15 @@
     arg_renderbuffers->add_intvalue((int)renderbuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteRenderbuffersOES(n, renderbuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13491,11 +15103,15 @@
     arg_renderbuffers->add_intvalue((int)renderbuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenRenderbuffersOES(n, renderbuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13530,11 +15146,15 @@
     arg_height->add_intvalue(height);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glRenderbufferStorageOES(target, internalformat, width, height);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13563,11 +15183,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetRenderbufferParameterivOES(target, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13584,9 +15208,11 @@
     arg_framebuffer->add_intvalue(framebuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLboolean retValue = glContext->hooks->gl.glIsFramebufferOES(framebuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13594,7 +15220,9 @@
     rt->set_type(GLMessage::DataType::BOOL);
     rt->add_boolvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -13619,11 +15247,15 @@
     arg_framebuffer->add_intvalue(framebuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glBindFramebufferOES(target, framebuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13646,11 +15278,15 @@
     arg_framebuffers->add_intvalue((int)framebuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDeleteFramebuffersOES(n, framebuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13673,11 +15309,15 @@
     arg_framebuffers->add_intvalue((int)framebuffers);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenFramebuffersOES(n, framebuffers);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13694,9 +15334,11 @@
     arg_target->add_intvalue((int)target);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLenum retValue = glContext->hooks->gl.glCheckFramebufferStatusOES(target);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13704,7 +15346,9 @@
     rt->set_type(GLMessage::DataType::ENUM);
     rt->add_intvalue((int)retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -13741,11 +15385,15 @@
     arg_renderbuffer->add_intvalue(renderbuffer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFramebufferRenderbufferOES(target, attachment, renderbuffertarget, renderbuffer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13786,11 +15434,15 @@
     arg_level->add_intvalue(level);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFramebufferTexture2DOES(target, attachment, textarget, texture, level);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13825,11 +15477,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetFramebufferAttachmentParameterivOES(target, attachment, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13846,11 +15502,15 @@
     arg_target->add_intvalue((int)target);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGenerateMipmapOES(target);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13867,11 +15527,15 @@
     arg_matrixpaletteindex->add_intvalue(matrixpaletteindex);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glCurrentPaletteMatrixOES(matrixpaletteindex);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13882,11 +15546,15 @@
     glmsg.set_function(GLMessage::glLoadPaletteFromModelViewMatrixOES);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glLoadPaletteFromModelViewMatrixOES();
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13921,11 +15589,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glMatrixIndexPointerOES(size, type, stride, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13960,11 +15632,15 @@
     arg_pointer->add_intvalue((int)pointer);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glWeightPointerOES(size, type, stride, pointer);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -13987,9 +15663,11 @@
     arg_exponent->add_intvalue((int)exponent);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     GLbitfield retValue = glContext->hooks->gl.glQueryMatrixxOES(mantissa, exponent);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
     // set return value
     GLMessage_DataType *rt = glmsg.mutable_returnvalue();
@@ -13997,7 +15675,9 @@
     rt->set_type(GLMessage::DataType::INT);
     rt->add_intvalue(retValue);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 
     return retValue;
@@ -14022,11 +15702,15 @@
     arg_zFar->add_floatvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glDepthRangefOES(zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14073,11 +15757,15 @@
     arg_zFar->add_floatvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glFrustumfOES(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14124,11 +15812,15 @@
     arg_zFar->add_floatvalue(zFar);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glOrthofOES(left, right, bottom, top, zNear, zFar);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14151,11 +15843,15 @@
     arg_equation->add_intvalue((int)equation);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClipPlanefOES(plane, equation);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14178,11 +15874,15 @@
     arg_eqn->add_intvalue((int)eqn);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetClipPlanefOES(pname, eqn);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14199,11 +15899,15 @@
     arg_depth->add_floatvalue(depth);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClearDepthfOES(depth);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14232,11 +15936,15 @@
     arg_param->add_floatvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexGenfOES(coord, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14265,11 +15973,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexGenfvOES(coord, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14298,11 +16010,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexGeniOES(coord, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14331,11 +16047,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexGenivOES(coord, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14364,11 +16084,15 @@
     arg_param->add_intvalue(param);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexGenxOES(coord, pname, param);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14397,11 +16121,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glTexGenxvOES(coord, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14430,11 +16158,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexGenfvOES(coord, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14463,11 +16195,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexGenivOES(coord, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14496,11 +16232,15 @@
     arg_params->add_intvalue((int)params);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glGetTexGenxvOES(coord, pname, params);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14523,11 +16263,15 @@
     arg_eqn->add_intvalue((int)eqn);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClipPlanefIMG(p, eqn);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
@@ -14550,11 +16294,15 @@
     arg_eqn->add_intvalue((int)eqn);
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
     glContext->hooks->gl.glClipPlanexIMG(p, eqn);
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 }
 
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index 3e185bc..6c4feb5 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -379,13 +379,16 @@
     arg_location->add_intvalue(location);
 }
 
-void fixupGLMessage(GLTraceContext *context, nsecs_t start, nsecs_t end, GLMessage *glmsg) {
+void fixupGLMessage(GLTraceContext *context, nsecs_t wallStart, nsecs_t wallEnd,
+                                             nsecs_t threadStart, nsecs_t threadEnd,
+                                             GLMessage *glmsg) {
     // for all messages, set the current context id
     glmsg->set_context_id(context->getId());
 
     // set start time and duration
-    glmsg->set_start_time(start);
-    glmsg->set_duration((unsigned)(end - start));
+    glmsg->set_start_time(wallStart);
+    glmsg->set_duration((unsigned)(wallEnd - wallStart));
+    glmsg->set_threadtime((unsigned)(threadEnd - threadStart));
 
     // do any custom message dependent processing
     switch (glmsg->function()) {
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.h b/opengl/libs/GLES_trace/src/gltrace_fixup.h
index 64f7545..f63b056 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.h
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.h
@@ -25,7 +25,9 @@
 namespace android {
 namespace gltrace {
 
-void fixupGLMessage(GLTraceContext *curContext, nsecs_t start, nsecs_t end, GLMessage *message);
+void fixupGLMessage(GLTraceContext *curContext, nsecs_t wallStart, nsecs_t wallEnd,
+                                                nsecs_t threadStart, nsecs_t threadEnd,
+                                                GLMessage *message);
 void fixup_addFBContents(GLTraceContext *curContext, GLMessage *message, FBBinding fbToRead);
 
 };
diff --git a/opengl/libs/GLES_trace/tools/genapi.py b/opengl/libs/GLES_trace/tools/genapi.py
index 557e407..e1660be 100755
--- a/opengl/libs/GLES_trace/tools/genapi.py
+++ b/opengl/libs/GLES_trace/tools/genapi.py
@@ -162,13 +162,15 @@
 <!--(end)-->
 
     // call function
-    nsecs_t start_time = systemTime();
+    nsecs_t wallStartTime = systemTime(SYSTEM_TIME_MONOTONIC);
+    nsecs_t threadStartTime = systemTime(SYSTEM_TIME_THREAD);
 <!--(if retType != "void")-->
     $!retType!$ retValue = glContext->hooks->gl.$!callsite!$;
 <!--(else)-->
     glContext->hooks->gl.$!callsite!$;
 <!--(end)-->
-    nsecs_t end_time = systemTime();
+    nsecs_t threadEndTime = systemTime(SYSTEM_TIME_THREAD);
+    nsecs_t wallEndTime = systemTime(SYSTEM_TIME_MONOTONIC);
 <!--(if retType != "void")-->
 
     // set return value
@@ -178,7 +180,9 @@
     rt->$!retDataType.getProtobufCall()!$retValue);
 <!--(end)-->
 
-    fixupGLMessage(glContext, start_time, end_time, &glmsg);
+    fixupGLMessage(glContext, wallStartTime, wallEndTime,
+                              threadStartTime, threadEndTime,
+                              &glmsg);
     glContext->traceGLMessage(&glmsg);
 <!--(if retType != "void")-->
 
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 3beaac9..3a8e3fc 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -148,4 +148,7 @@
     <!-- Development settings -->
     <bool name="def_stay_on_while_plugged_in">false</bool>
 
+    <!-- Number of retries for connecting to DHCP.
+         Value here is the same as WifiStateMachine.DEFAULT_MAX_DHCP_RETRIES -->
+    <integer name="def_max_dhcp_retries">9</integer>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index 882aa66..330a189 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1602,6 +1602,9 @@
 
             loadBooleanSetting(stmt, Settings.Secure.NETSTATS_ENABLED,
                     R.bool.def_netstats_enabled);
+
+            loadIntegerSetting(stmt, Settings.Secure.WIFI_MAX_DHCP_RETRY_COUNT,
+                    R.integer.def_max_dhcp_retries);
         } finally {
             if (stmt != null) stmt.close();
         }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index b87b8c3..301dbf5 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -115,6 +115,10 @@
 
     final TypedValue mMinWidthMajor = new TypedValue();
     final TypedValue mMinWidthMinor = new TypedValue();
+    TypedValue mFixedWidthMajor;
+    TypedValue mFixedWidthMinor;
+    TypedValue mFixedHeightMajor;
+    TypedValue mFixedHeightMinor;
 
     // This is the top-level view of the window, containing the window decor.
     private DecorView mDecor;
@@ -2088,6 +2092,44 @@
             final boolean isPortrait = metrics.widthPixels < metrics.heightPixels;
 
             final int widthMode = getMode(widthMeasureSpec);
+            final int heightMode = getMode(heightMeasureSpec);
+
+            boolean fixedWidth = false;
+            if (widthMode == AT_MOST) {
+                final TypedValue tvw = isPortrait ? mFixedWidthMinor : mFixedWidthMajor;
+                if (tvw != null && tvw.type != TypedValue.TYPE_NULL) {
+                    fixedWidth = true;
+                    final int w;
+                    if (tvw.type == TypedValue.TYPE_DIMENSION) {
+                        w = (int) tvw.getDimension(metrics);
+                    } else if (tvw.type == TypedValue.TYPE_FRACTION) {
+                        w = (int) tvw.getFraction(metrics.widthPixels, metrics.widthPixels);
+                    } else {
+                        w = 0;
+                    }
+
+                    final int widthSize = MeasureSpec.getSize(widthMeasureSpec);
+                    widthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.min(w, widthSize), EXACTLY);
+                }
+            }
+
+            if (heightMode == AT_MOST) {
+                final TypedValue tvh = isPortrait ? mFixedHeightMajor : mFixedHeightMinor;
+                if (tvh != null && tvh.type != TypedValue.TYPE_NULL) {
+                    final int h;
+                    if (tvh.type == TypedValue.TYPE_DIMENSION) {
+                        h = (int) tvh.getDimension(metrics);
+                    } else if (tvh.type == TypedValue.TYPE_FRACTION) {
+                        h = (int) tvh.getFraction(metrics.heightPixels, metrics.heightPixels);
+                    } else {
+                        h = 0;
+                    }
+
+                    final int heightSize = MeasureSpec.getSize(heightMeasureSpec);
+                    heightMeasureSpec =
+                            MeasureSpec.makeMeasureSpec(Math.min(h, heightSize), EXACTLY);
+                }
+            }
 
             super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
@@ -2096,21 +2138,22 @@
 
             widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, EXACTLY);
 
-            final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
+            if (!fixedWidth && widthMode == AT_MOST) {
+                final TypedValue tv = isPortrait ? mMinWidthMinor : mMinWidthMajor;
+                if (tv.type != TypedValue.TYPE_NULL) {
+                    final int min;
+                    if (tv.type == TypedValue.TYPE_DIMENSION) {
+                        min = (int)tv.getDimension(metrics);
+                    } else if (tv.type == TypedValue.TYPE_FRACTION) {
+                        min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
+                    } else {
+                        min = 0;
+                    }
 
-            if (widthMode == AT_MOST && tv.type != TypedValue.TYPE_NULL) {
-                final int min;
-                if (tv.type == TypedValue.TYPE_DIMENSION) {
-                    min = (int)tv.getDimension(metrics);
-                } else if (tv.type == TypedValue.TYPE_FRACTION) {
-                    min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels);
-                } else {
-                    min = 0;
-                }
-
-                if (width < min) {
-                    widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
-                    measure = true;
+                    if (width < min) {
+                        widthMeasureSpec = MeasureSpec.makeMeasureSpec(min, EXACTLY);
+                        measure = true;
+                    }
                 }
             }
 
@@ -2571,6 +2614,26 @@
 
         a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMajor, mMinWidthMajor);
         a.getValue(com.android.internal.R.styleable.Window_windowMinWidthMinor, mMinWidthMinor);
+        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor)) {
+            if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue();
+            a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMajor,
+                    mFixedWidthMajor);
+        }
+        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor)) {
+            if (mFixedWidthMinor == null) mFixedWidthMinor = new TypedValue();
+            a.getValue(com.android.internal.R.styleable.Window_windowFixedWidthMinor,
+                    mFixedWidthMinor);
+        }
+        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor)) {
+            if (mFixedHeightMajor == null) mFixedHeightMajor = new TypedValue();
+            a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMajor,
+                    mFixedHeightMajor);
+        }
+        if (a.hasValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor)) {
+            if (mFixedHeightMinor == null) mFixedHeightMinor = new TypedValue();
+            a.getValue(com.android.internal.R.styleable.Window_windowFixedHeightMinor,
+                    mFixedHeightMinor);
+        }
 
         final Context context = getContext();
         final int targetSdk = context.getApplicationInfo().targetSdkVersion;
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 157405a..22fa752 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -7,6 +7,7 @@
     AudioMixer.cpp.arm          \
     AudioResampler.cpp.arm      \
     AudioPolicyService.cpp      \
+    AudioBufferProvider.cpp     \
     ServiceUtilities.cpp
 #   AudioResamplerSinc.cpp.arm
 #   AudioResamplerCubic.cpp.arm
@@ -17,6 +18,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libaudioutils \
+    libcommon_time_client \
     libcutils \
     libutils \
     libbinder \
diff --git a/include/ui/PowerManager.h b/services/audioflinger/AudioBufferProvider.cpp
similarity index 61%
copy from include/ui/PowerManager.h
copy to services/audioflinger/AudioBufferProvider.cpp
index dd80318..678fd58 100644
--- a/include/ui/PowerManager.h
+++ b/services/audioflinger/AudioBufferProvider.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2010 The Android Open Source Project
+ * Copyright (C) 2011 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.
@@ -14,20 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef _UI_POWER_MANAGER_H
-#define _UI_POWER_MANAGER_H
+#undef __STRICT_ANSI__
+#define __STDINT_LIMITS
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
 
+#include "AudioBufferProvider.h"
 
 namespace android {
 
-enum {
-    POWER_MANAGER_OTHER_EVENT = 0,
-    POWER_MANAGER_BUTTON_EVENT = 1,
-    POWER_MANAGER_TOUCH_EVENT = 2,
+const int64_t AudioBufferProvider::kInvalidPTS = INT64_MAX;
 
-    POWER_MANAGER_LAST_EVENT = POWER_MANAGER_TOUCH_EVENT, // Last valid event code.
-};
-
-} // namespace android
-
-#endif // _UI_POWER_MANAGER_H
+}; // namespace android
diff --git a/services/audioflinger/AudioBufferProvider.h b/services/audioflinger/AudioBufferProvider.h
index 81c5c39..62ad6bd 100644
--- a/services/audioflinger/AudioBufferProvider.h
+++ b/services/audioflinger/AudioBufferProvider.h
@@ -38,8 +38,15 @@
     };
 
     virtual ~AudioBufferProvider() {}
-    
-    virtual status_t getNextBuffer(Buffer* buffer) = 0;
+
+    // value representing an invalid presentation timestamp
+    static const int64_t kInvalidPTS;
+
+    // pts is the local time when the next sample yielded by getNextBuffer
+    // will be rendered.
+    // Pass kInvalidPTS if the PTS is unknown or not applicable.
+    virtual status_t getNextBuffer(Buffer* buffer, int64_t pts) = 0;
+
     virtual void releaseBuffer(Buffer* buffer) = 0;
 };
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 0248687..2e2834c 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -61,6 +61,9 @@
 #include <powermanager/PowerManager.h>
 // #define DEBUG_CPU_USAGE 10  // log statistics every n wall clock seconds
 
+#include <common_time/cc_helper.h>
+#include <common_time/local_clock.h>
+
 // ----------------------------------------------------------------------------
 
 
@@ -69,7 +72,6 @@
 static const char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
 static const char kHardwareLockedString[] = "Hardware lock is taken\n";
 
-//static const nsecs_t kStandbyTimeInNsecs = seconds(3);
 static const float MAX_GAIN = 4096.0f;
 static const uint32_t MAX_GAIN_INT = 0x1000;
 
@@ -99,6 +101,7 @@
 // maximum divider applied to the active sleep time in the mixer thread loop
 static const uint32_t kMaxThreadSleepTimeShift = 2;
 
+nsecs_t AudioFlinger::mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
 
 // ----------------------------------------------------------------------------
 
@@ -147,11 +150,14 @@
 
 AudioFlinger::AudioFlinger()
     : BnAudioFlinger(),
-        mPrimaryHardwareDev(NULL),
-        mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
-        mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1),
-        mMode(AUDIO_MODE_INVALID),
-        mBtNrecIsOff(false)
+      mPrimaryHardwareDev(NULL),
+      mHardwareStatus(AUDIO_HW_IDLE), // see also onFirstRef()
+      mMasterVolume(1.0f),
+      mMasterVolumeSupportLvl(MVS_NONE),
+      mMasterMute(false),
+      mNextUniqueId(1),
+      mMode(AUDIO_MODE_INVALID),
+      mBtNrecIsOff(false)
 {
 }
 
@@ -162,6 +168,18 @@
     Mutex::Autolock _l(mLock);
 
     /* TODO: move all this work into an Init() function */
+    char val_str[PROPERTY_VALUE_MAX] = { 0 };
+    if (property_get("ro.audio.flinger_standbytime_ms", val_str, NULL) >= 0) {
+        uint32_t int_val;
+        if (1 == sscanf(val_str, "%u", &int_val)) {
+            mStandbyTimeInNsecs = milliseconds(int_val);
+            ALOGI("Using %u mSec as standby time.", int_val);
+        } else {
+            mStandbyTimeInNsecs = kDefaultStandbyTimeInNsecs;
+            ALOGI("Using default %u mSec as standby time.",
+                    (uint32_t)(mStandbyTimeInNsecs / 1000000));
+        }
+    }
 
     for (size_t i = 0; i < ARRAY_SIZE(audio_interfaces); i++) {
         const hw_module_t *mod;
@@ -193,6 +211,32 @@
 
     AutoMutex lock(mHardwareLock);
 
+    // Determine the level of master volume support the primary audio HAL has,
+    // and set the initial master volume at the same time.
+    float initialVolume = 1.0;
+    mMasterVolumeSupportLvl = MVS_NONE;
+    if (0 == mPrimaryHardwareDev->init_check(mPrimaryHardwareDev)) {
+        audio_hw_device_t *dev = mPrimaryHardwareDev;
+
+        mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+        if ((NULL != dev->get_master_volume) &&
+            (NO_ERROR == dev->get_master_volume(dev, &initialVolume))) {
+            mMasterVolumeSupportLvl = MVS_FULL;
+        } else {
+            mMasterVolumeSupportLvl = MVS_SETONLY;
+            initialVolume = 1.0;
+        }
+
+        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+        if ((NULL == dev->set_master_volume) ||
+            (NO_ERROR != dev->set_master_volume(dev, initialVolume))) {
+            mMasterVolumeSupportLvl = MVS_NONE;
+        }
+        mHardwareStatus = AUDIO_HW_INIT;
+    }
+
+    // Set the mode for each audio HAL, and try to set the initial volume (if
+    // supported) for all of the non-primary audio HALs.
     for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
         audio_hw_device_t *dev = mAudioHwDevs[i];
 
@@ -203,11 +247,22 @@
             mMode = AUDIO_MODE_NORMAL;  // assigned multiple times with same value
             mHardwareStatus = AUDIO_HW_SET_MODE;
             dev->set_mode(dev, mMode);
-            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-            dev->set_master_volume(dev, 1.0f);
-            mHardwareStatus = AUDIO_HW_IDLE;
+
+            if ((dev != mPrimaryHardwareDev) &&
+                (NULL != dev->set_master_volume)) {
+                mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+                dev->set_master_volume(dev, initialVolume);
+            }
+
+            mHardwareStatus = AUDIO_HW_INIT;
         }
     }
+
+    mMasterVolumeSW = (MVS_NONE == mMasterVolumeSupportLvl)
+                    ? initialVolume
+                    : 1.0;
+    mMasterVolume   = initialVolume;
+    mHardwareStatus = AUDIO_HW_IDLE;
 }
 
 AudioFlinger::~AudioFlinger()
@@ -273,7 +328,10 @@
     String8 result;
     hardware_call_state hardwareStatus = mHardwareStatus;
 
-    snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
+    snprintf(buffer, SIZE, "Hardware status: %d\n"
+                           "Standby Time mSec: %u\n",
+                            hardwareStatus,
+                            (uint32_t)(mStandbyTimeInNsecs / 1000000));
     result.append(buffer);
     write(fd, result.string(), result.size());
     return NO_ERROR;
@@ -377,6 +435,7 @@
         uint32_t flags,
         const sp<IMemory>& sharedBuffer,
         audio_io_handle_t output,
+        bool isTimed,
         int *sessionId,
         status_t *status)
 {
@@ -435,7 +494,7 @@
         ALOGV("createTrack() lSessionId: %d", lSessionId);
 
         track = thread->createTrack_l(client, streamType, sampleRate, format,
-                channelMask, frameCount, sharedBuffer, lSessionId, &lStatus);
+                channelMask, frameCount, sharedBuffer, lSessionId, isTimed, &lStatus);
 
         // move effect chain to this output thread if an effect on same session was waiting
         // for a track to be created
@@ -528,20 +587,29 @@
         return PERMISSION_DENIED;
     }
 
+    float swmv = value;
+
     // when hw supports master volume, don't scale in sw mixer
-    { // scope for the lock
-        AutoMutex lock(mHardwareLock);
-        mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
-        if (mPrimaryHardwareDev->set_master_volume(mPrimaryHardwareDev, value) == NO_ERROR) {
-            value = 1.0f;
+    if (MVS_NONE != mMasterVolumeSupportLvl) {
+        for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+            AutoMutex lock(mHardwareLock);
+            audio_hw_device_t *dev = mAudioHwDevs[i];
+
+            mHardwareStatus = AUDIO_HW_SET_MASTER_VOLUME;
+            if (NULL != dev->set_master_volume) {
+                dev->set_master_volume(dev, value);
+            }
+            mHardwareStatus = AUDIO_HW_IDLE;
         }
-        mHardwareStatus = AUDIO_HW_IDLE;
+
+        swmv = 1.0;
     }
 
     Mutex::Autolock _l(mLock);
-    mMasterVolume = value;
+    mMasterVolume   = value;
+    mMasterVolumeSW = swmv;
     for (size_t i = 0; i < mPlaybackThreads.size(); i++)
-       mPlaybackThreads.valueAt(i)->setMasterVolume(value);
+       mPlaybackThreads.valueAt(i)->setMasterVolume(swmv);
 
     return NO_ERROR;
 }
@@ -635,12 +703,36 @@
     return masterVolume_l();
 }
 
+float AudioFlinger::masterVolumeSW() const
+{
+    Mutex::Autolock _l(mLock);
+    return masterVolumeSW_l();
+}
+
 bool AudioFlinger::masterMute() const
 {
     Mutex::Autolock _l(mLock);
     return masterMute_l();
 }
 
+float AudioFlinger::masterVolume_l() const
+{
+    if (MVS_FULL == mMasterVolumeSupportLvl) {
+        float ret_val;
+        AutoMutex lock(mHardwareLock);
+
+        mHardwareStatus = AUDIO_HW_GET_MASTER_VOLUME;
+        assert(NULL != mPrimaryHardwareDev);
+        assert(NULL != mPrimaryHardwareDev->get_master_volume);
+
+        mPrimaryHardwareDev->get_master_volume(mPrimaryHardwareDev, &ret_val);
+        mHardwareStatus = AUDIO_HW_IDLE;
+        return ret_val;
+    }
+
+    return mMasterVolume;
+}
+
 status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
         audio_io_handle_t output)
 {
@@ -814,7 +906,7 @@
         for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
             audio_hw_device_t *dev = mAudioHwDevs[i];
             char *s = dev->get_parameters(dev, keys.string());
-            out_s8 += String8(s);
+            out_s8 += String8(s ? s : "");
             free(s);
         }
         return out_s8;
@@ -1367,7 +1459,7 @@
         mOutput(output),
         // Assumes constructor is called by AudioFlinger with it's mLock held,
         // but it would be safer to explicitly pass initial masterVolume as parameter
-        mMasterVolume(audioFlinger->masterVolume_l()),
+        mMasterVolume(audioFlinger->masterVolumeSW_l()),
         mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
 {
     snprintf(mName, kNameLength, "AudioOut_%d", id);
@@ -1485,6 +1577,7 @@
         int frameCount,
         const sp<IMemory>& sharedBuffer,
         int sessionId,
+        bool isTimed,
         status_t *status)
 {
     sp<Track> track;
@@ -1535,9 +1628,14 @@
             }
         }
 
-        track = new Track(this, client, streamType, sampleRate, format,
-                channelMask, frameCount, sharedBuffer, sessionId);
-        if (track->getCblk() == NULL || track->name() < 0) {
+        if (!isTimed) {
+            track = new Track(this, client, streamType, sampleRate, format,
+                    channelMask, frameCount, sharedBuffer, sessionId);
+        } else {
+            track = TimedTrack::create(this, client, streamType, sampleRate, format,
+                    channelMask, frameCount, sharedBuffer, sessionId);
+        }
+        if (track == NULL || track->getCblk() == NULL || track->name() < 0) {
             lStatus = NO_MEMORY;
             goto Exit;
         }
@@ -1941,7 +2039,7 @@
                         }
                     }
 
-                    standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    standbyTime = systemTime() + mStandbyTimeInNsecs;
                     sleepTime = idleSleepTime;
                     sleepTimeShift = 0;
                     continue;
@@ -1957,8 +2055,21 @@
         }
 
         if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
+            // obtain the presentation timestamp of the next output buffer
+            int64_t pts;
+            status_t status = INVALID_OPERATION;
+
+            if (NULL != mOutput->stream->get_next_write_timestamp) {
+                status = mOutput->stream->get_next_write_timestamp(
+                        mOutput->stream, &pts);
+            }
+
+            if (status != NO_ERROR) {
+                pts = AudioBufferProvider::kInvalidPTS;
+            }
+
             // mix buffers...
-            mAudioMixer->process();
+            mAudioMixer->process(pts);
             // increase sleep time progressively when application underrun condition clears.
             // Only increase sleep time if the mixer is ready for two consecutive times to avoid
             // that a steady state of alternating ready/not ready conditions keeps the sleep time
@@ -1967,7 +2078,7 @@
                 sleepTimeShift--;
             }
             sleepTime = 0;
-            standbyTime = systemTime() + kStandbyTimeInNsecs;
+            standbyTime = systemTime() + mStandbyTimeInNsecs;
             //TODO: delay standby when effects have a tail
         } else {
             // If no tracks are ready, sleep once for the duration of an output
@@ -2114,7 +2225,7 @@
                 ALOG_ASSERT(minFrames <= cblk->frameCount);
             }
         }
-        if ((cblk->framesReady() >= minFrames) && track->isReady() &&
+        if ((track->framesReady() >= minFrames) && track->isReady() &&
                 !track->isPaused() && !track->isTerminated())
         {
             //ALOGV("track %d u=%08x, s=%08x [OK] on thread %p", name, cblk->user, cblk->server, this);
@@ -2184,7 +2295,7 @@
 
                 uint16_t sendLevel = cblk->getSendLevel_U4_12();
                 // send level comes from shared memory and so may be corrupt
-                if (sendLevel >= MAX_GAIN_INT) {
+                if (sendLevel > MAX_GAIN_INT) {
                     ALOGV("Track send level out of range: %04X", sendLevel);
                     sendLevel = MAX_GAIN_INT;
                 }
@@ -2205,25 +2316,21 @@
             }
 
             // Convert volumes from 8.24 to 4.12 format
-            int16_t left, right, aux;
             // This additional clamping is needed in case chain->setVolume_l() overshot
-            uint32_t v_clamped = (vl + (1 << 11)) >> 12;
-            if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
-            left = int16_t(v_clamped);
-            v_clamped = (vr + (1 << 11)) >> 12;
-            if (v_clamped > MAX_GAIN_INT) v_clamped = MAX_GAIN_INT;
-            right = int16_t(v_clamped);
+            vl = (vl + (1 << 11)) >> 12;
+            if (vl > MAX_GAIN_INT) vl = MAX_GAIN_INT;
+            vr = (vr + (1 << 11)) >> 12;
+            if (vr > MAX_GAIN_INT) vr = MAX_GAIN_INT;
 
-            if (va > MAX_GAIN_INT) va = MAX_GAIN_INT;
-            aux = int16_t(va);
+            if (va > MAX_GAIN_INT) va = MAX_GAIN_INT;   // va is uint32_t, so no need to check for -
 
             // XXX: these things DON'T need to be done each time
             mAudioMixer->setBufferProvider(name, track);
             mAudioMixer->enable(name);
 
-            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)left);
-            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)right);
-            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void *)aux);
+            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME0, (void *)vl);
+            mAudioMixer->setParameter(name, param, AudioMixer::VOLUME1, (void *)vr);
+            mAudioMixer->setParameter(name, param, AudioMixer::AUXLEVEL, (void *)va);
             mAudioMixer->setParameter(
                 name,
                 AudioMixer::TRACK,
@@ -2577,7 +2684,6 @@
     sp<Track> trackToRemove;
     sp<Track> activeTrack;
     nsecs_t standbyTime = systemTime();
-    int8_t *curBuf;
     size_t mixBufferSize = mFrameCount*mFrameSize;
     uint32_t activeSleepTime = activeSleepTimeUs();
     uint32_t idleSleepTime = idleSleepTimeUs();
@@ -2781,11 +2887,12 @@
         if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             AudioBufferProvider::Buffer buffer;
             size_t frameCount = mFrameCount;
-            curBuf = (int8_t *)mMixBuffer;
+            int8_t *curBuf = (int8_t *)mMixBuffer;
             // output audio to hardware
             while (frameCount) {
                 buffer.frameCount = frameCount;
-                activeTrack->getNextBuffer(&buffer);
+                activeTrack->getNextBuffer(&buffer,
+                                           AudioBufferProvider::kInvalidPTS);
                 if (CC_UNLIKELY(buffer.raw == NULL)) {
                     memset(curBuf, 0, frameCount * mFrameSize);
                     break;
@@ -3038,7 +3145,7 @@
                         }
                     }
 
-                    standbyTime = systemTime() + kStandbyTimeInNsecs;
+                    standbyTime = systemTime() + mStandbyTimeInNsecs;
                     sleepTime = idleSleepTime;
                     continue;
                 }
@@ -3055,7 +3162,7 @@
         if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
             // mix buffers...
             if (outputsReady(outputTracks)) {
-                mAudioMixer->process();
+                mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
             } else {
                 memset(mMixBuffer, 0, mixBufferSize);
             }
@@ -3092,7 +3199,7 @@
             // enable changes in effect chain
             unlockEffectChains(effectChains);
 
-            standbyTime = systemTime() + kStandbyTimeInNsecs;
+            standbyTime = systemTime() + mStandbyTimeInNsecs;
             for (size_t i = 0; i < outputTracks.size(); i++) {
                 outputTracks[i]->write(mMixBuffer, writeFrames);
             }
@@ -3142,7 +3249,7 @@
 {
     Mutex::Autolock _l(mLock);
     for (size_t i = 0; i < mOutputTracks.size(); i++) {
-        if (mOutputTracks[i]->thread() == (ThreadBase *)thread) {
+        if (mOutputTracks[i]->thread() == thread) {
             mOutputTracks[i]->destroy();
             mOutputTracks.removeAt(i);
             updateWaitTime();
@@ -3443,7 +3550,8 @@
             (int)mAuxBuffer);
 }
 
-status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::PlaybackThread::Track::getNextBuffer(
+    AudioBufferProvider::Buffer* buffer, int64_t pts)
 {
      audio_track_cblk_t* cblk = this->cblk();
      uint32_t framesReady;
@@ -3484,10 +3592,14 @@
      return NOT_ENOUGH_DATA;
 }
 
+uint32_t AudioFlinger::PlaybackThread::Track::framesReady() const{
+    return mCblk->framesReady();
+}
+
 bool AudioFlinger::PlaybackThread::Track::isReady() const {
     if (mFillingUpStatus != FS_FILLING || isStopped() || isPausing()) return true;
 
-    if (mCblk->framesReady() >= mCblk->frameCount ||
+    if (framesReady() >= mCblk->frameCount ||
             (mCblk->flags & CBLK_FORCEREADY_MSK)) {
         mFillingUpStatus = FS_FILLED;
         android_atomic_and(~CBLK_FORCEREADY_MSK, &mCblk->flags);
@@ -3644,6 +3756,406 @@
     mAuxBuffer = buffer;
 }
 
+// timed audio tracks
+
+sp<AudioFlinger::PlaybackThread::TimedTrack>
+AudioFlinger::PlaybackThread::TimedTrack::create(
+            const wp<ThreadBase>& thread,
+            const sp<Client>& client,
+            audio_stream_type_t streamType,
+            uint32_t sampleRate,
+            audio_format_t format,
+            uint32_t channelMask,
+            int frameCount,
+            const sp<IMemory>& sharedBuffer,
+            int sessionId) {
+    if (!client->reserveTimedTrack())
+        return NULL;
+
+    sp<TimedTrack> track = new TimedTrack(
+        thread, client, streamType, sampleRate, format, channelMask, frameCount,
+        sharedBuffer, sessionId);
+
+    if (track == NULL) {
+        client->releaseTimedTrack();
+        return NULL;
+    }
+
+    return track;
+}
+
+AudioFlinger::PlaybackThread::TimedTrack::TimedTrack(
+            const wp<ThreadBase>& thread,
+            const sp<Client>& client,
+            audio_stream_type_t streamType,
+            uint32_t sampleRate,
+            audio_format_t format,
+            uint32_t channelMask,
+            int frameCount,
+            const sp<IMemory>& sharedBuffer,
+            int sessionId)
+    : Track(thread, client, streamType, sampleRate, format, channelMask,
+            frameCount, sharedBuffer, sessionId),
+      mTimedSilenceBuffer(NULL),
+      mTimedSilenceBufferSize(0),
+      mTimedAudioOutputOnTime(false),
+      mMediaTimeTransformValid(false)
+{
+    LocalClock lc;
+    mLocalTimeFreq = lc.getLocalFreq();
+
+    mLocalTimeToSampleTransform.a_zero = 0;
+    mLocalTimeToSampleTransform.b_zero = 0;
+    mLocalTimeToSampleTransform.a_to_b_numer = sampleRate;
+    mLocalTimeToSampleTransform.a_to_b_denom = mLocalTimeFreq;
+    LinearTransform::reduce(&mLocalTimeToSampleTransform.a_to_b_numer,
+                            &mLocalTimeToSampleTransform.a_to_b_denom);
+}
+
+AudioFlinger::PlaybackThread::TimedTrack::~TimedTrack() {
+    mClient->releaseTimedTrack();
+    delete [] mTimedSilenceBuffer;
+}
+
+status_t AudioFlinger::PlaybackThread::TimedTrack::allocateTimedBuffer(
+    size_t size, sp<IMemory>* buffer) {
+
+    Mutex::Autolock _l(mTimedBufferQueueLock);
+
+    trimTimedBufferQueue_l();
+
+    // lazily initialize the shared memory heap for timed buffers
+    if (mTimedMemoryDealer == NULL) {
+        const int kTimedBufferHeapSize = 512 << 10;
+
+        mTimedMemoryDealer = new MemoryDealer(kTimedBufferHeapSize,
+                                              "AudioFlingerTimed");
+        if (mTimedMemoryDealer == NULL)
+            return NO_MEMORY;
+    }
+
+    sp<IMemory> newBuffer = mTimedMemoryDealer->allocate(size);
+    if (newBuffer == NULL) {
+        newBuffer = mTimedMemoryDealer->allocate(size);
+        if (newBuffer == NULL)
+            return NO_MEMORY;
+    }
+
+    *buffer = newBuffer;
+    return NO_ERROR;
+}
+
+// caller must hold mTimedBufferQueueLock
+void AudioFlinger::PlaybackThread::TimedTrack::trimTimedBufferQueue_l() {
+    int64_t mediaTimeNow;
+    {
+        Mutex::Autolock mttLock(mMediaTimeTransformLock);
+        if (!mMediaTimeTransformValid)
+            return;
+
+        int64_t targetTimeNow;
+        status_t res = (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME)
+            ? mCCHelper.getCommonTime(&targetTimeNow)
+            : mCCHelper.getLocalTime(&targetTimeNow);
+
+        if (OK != res)
+            return;
+
+        if (!mMediaTimeTransform.doReverseTransform(targetTimeNow,
+                                                    &mediaTimeNow)) {
+            return;
+        }
+    }
+
+    size_t trimIndex;
+    for (trimIndex = 0; trimIndex < mTimedBufferQueue.size(); trimIndex++) {
+        if (mTimedBufferQueue[trimIndex].pts() > mediaTimeNow)
+            break;
+    }
+
+    if (trimIndex) {
+        mTimedBufferQueue.removeItemsAt(0, trimIndex);
+    }
+}
+
+status_t AudioFlinger::PlaybackThread::TimedTrack::queueTimedBuffer(
+    const sp<IMemory>& buffer, int64_t pts) {
+
+    {
+        Mutex::Autolock mttLock(mMediaTimeTransformLock);
+        if (!mMediaTimeTransformValid)
+            return INVALID_OPERATION;
+    }
+
+    Mutex::Autolock _l(mTimedBufferQueueLock);
+
+    mTimedBufferQueue.add(TimedBuffer(buffer, pts));
+
+    return NO_ERROR;
+}
+
+status_t AudioFlinger::PlaybackThread::TimedTrack::setMediaTimeTransform(
+    const LinearTransform& xform, TimedAudioTrack::TargetTimeline target) {
+
+    ALOGV("%s az=%lld bz=%lld n=%d d=%u tgt=%d", __PRETTY_FUNCTION__,
+         xform.a_zero, xform.b_zero, xform.a_to_b_numer, xform.a_to_b_denom,
+         target);
+
+    if (!(target == TimedAudioTrack::LOCAL_TIME ||
+          target == TimedAudioTrack::COMMON_TIME)) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMediaTimeTransformLock);
+    mMediaTimeTransform = xform;
+    mMediaTimeTransformTarget = target;
+    mMediaTimeTransformValid = true;
+
+    return NO_ERROR;
+}
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+
+// implementation of getNextBuffer for tracks whose buffers have timestamps
+status_t AudioFlinger::PlaybackThread::TimedTrack::getNextBuffer(
+    AudioBufferProvider::Buffer* buffer, int64_t pts)
+{
+    if (pts == AudioBufferProvider::kInvalidPTS) {
+        buffer->raw = 0;
+        buffer->frameCount = 0;
+        return INVALID_OPERATION;
+    }
+
+    // get ahold of the output stream that these samples will be written to
+    sp<ThreadBase> thread = mThread.promote();
+    if (thread == NULL) {
+        buffer->raw = 0;
+        buffer->frameCount = 0;
+        return INVALID_OPERATION;
+    }
+    PlaybackThread* playbackThread = static_cast<PlaybackThread*>(thread.get());
+
+    Mutex::Autolock _l(mTimedBufferQueueLock);
+
+    while (true) {
+
+        // if we have no timed buffers, then fail
+        if (mTimedBufferQueue.isEmpty()) {
+            buffer->raw = 0;
+            buffer->frameCount = 0;
+            return NOT_ENOUGH_DATA;
+        }
+
+        TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
+
+        // calculate the PTS of the head of the timed buffer queue expressed in
+        // local time
+        int64_t headLocalPTS;
+        {
+            Mutex::Autolock mttLock(mMediaTimeTransformLock);
+
+            assert(mMediaTimeTransformValid);
+
+            if (mMediaTimeTransform.a_to_b_denom == 0) {
+                // the transform represents a pause, so yield silence
+                timedYieldSilence(buffer->frameCount, buffer);
+                return NO_ERROR;
+            }
+
+            int64_t transformedPTS;
+            if (!mMediaTimeTransform.doForwardTransform(head.pts(),
+                                                        &transformedPTS)) {
+                // the transform failed.  this shouldn't happen, but if it does
+                // then just drop this buffer
+                ALOGW("timedGetNextBuffer transform failed");
+                buffer->raw = 0;
+                buffer->frameCount = 0;
+                mTimedBufferQueue.removeAt(0);
+                return NO_ERROR;
+            }
+
+            if (mMediaTimeTransformTarget == TimedAudioTrack::COMMON_TIME) {
+                if (OK != mCCHelper.commonTimeToLocalTime(transformedPTS,
+                                                          &headLocalPTS)) {
+                    buffer->raw = 0;
+                    buffer->frameCount = 0;
+                    return INVALID_OPERATION;
+                }
+            } else {
+                headLocalPTS = transformedPTS;
+            }
+        }
+
+        // adjust the head buffer's PTS to reflect the portion of the head buffer
+        // that has already been consumed
+        int64_t effectivePTS = headLocalPTS +
+                ((head.position() / mCblk->frameSize) * mLocalTimeFreq / sampleRate());
+
+        // Calculate the delta in samples between the head of the input buffer
+        // queue and the start of the next output buffer that will be written.
+        // If the transformation fails because of over or underflow, it means
+        // that the sample's position in the output stream is so far out of
+        // whack that it should just be dropped.
+        int64_t sampleDelta;
+        if (llabs(effectivePTS - pts) >= (static_cast<int64_t>(1) << 31)) {
+            ALOGV("*** head buffer is too far from PTS: dropped buffer");
+            mTimedBufferQueue.removeAt(0);
+            continue;
+        }
+        if (!mLocalTimeToSampleTransform.doForwardTransform(
+                (effectivePTS - pts) << 32, &sampleDelta)) {
+            ALOGV("*** too late during sample rate transform: dropped buffer");
+            mTimedBufferQueue.removeAt(0);
+            continue;
+        }
+
+        ALOGV("*** %s head.pts=%lld head.pos=%d pts=%lld sampleDelta=[%d.%08x]",
+             __PRETTY_FUNCTION__, head.pts(), head.position(), pts,
+             static_cast<int32_t>((sampleDelta >= 0 ? 0 : 1) + (sampleDelta >> 32)),
+             static_cast<uint32_t>(sampleDelta & 0xFFFFFFFF));
+
+        // if the delta between the ideal placement for the next input sample and
+        // the current output position is within this threshold, then we will
+        // concatenate the next input samples to the previous output
+        const int64_t kSampleContinuityThreshold =
+                (static_cast<int64_t>(sampleRate()) << 32) / 10;
+
+        // if this is the first buffer of audio that we're emitting from this track
+        // then it should be almost exactly on time.
+        const int64_t kSampleStartupThreshold = 1LL << 32;
+
+        if ((mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleContinuityThreshold) ||
+            (!mTimedAudioOutputOnTime && llabs(sampleDelta) <= kSampleStartupThreshold)) {
+            // the next input is close enough to being on time, so concatenate it
+            // with the last output
+            timedYieldSamples(buffer);
+
+            ALOGV("*** on time: head.pos=%d frameCount=%u", head.position(), buffer->frameCount);
+            return NO_ERROR;
+        } else if (sampleDelta > 0) {
+            // the gap between the current output position and the proper start of
+            // the next input sample is too big, so fill it with silence
+            uint32_t framesUntilNextInput = (sampleDelta + 0x80000000) >> 32;
+
+            timedYieldSilence(framesUntilNextInput, buffer);
+            ALOGV("*** silence: frameCount=%u", buffer->frameCount);
+            return NO_ERROR;
+        } else {
+            // the next input sample is late
+            uint32_t lateFrames = static_cast<uint32_t>(-((sampleDelta + 0x80000000) >> 32));
+            size_t onTimeSamplePosition =
+                    head.position() + lateFrames * mCblk->frameSize;
+
+            if (onTimeSamplePosition > head.buffer()->size()) {
+                // all the remaining samples in the head are too late, so
+                // drop it and move on
+                ALOGV("*** too late: dropped buffer");
+                mTimedBufferQueue.removeAt(0);
+                continue;
+            } else {
+                // skip over the late samples
+                head.setPosition(onTimeSamplePosition);
+
+                // yield the available samples
+                timedYieldSamples(buffer);
+
+                ALOGV("*** late: head.pos=%d frameCount=%u", head.position(), buffer->frameCount);
+                return NO_ERROR;
+            }
+        }
+    }
+}
+
+// Yield samples from the timed buffer queue head up to the given output
+// buffer's capacity.
+//
+// Caller must hold mTimedBufferQueueLock
+void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSamples(
+    AudioBufferProvider::Buffer* buffer) {
+
+    const TimedBuffer& head = mTimedBufferQueue[0];
+
+    buffer->raw = (static_cast<uint8_t*>(head.buffer()->pointer()) +
+                   head.position());
+
+    uint32_t framesLeftInHead = ((head.buffer()->size() - head.position()) /
+                                 mCblk->frameSize);
+    size_t framesRequested = buffer->frameCount;
+    buffer->frameCount = min(framesLeftInHead, framesRequested);
+
+    mTimedAudioOutputOnTime = true;
+}
+
+// Yield samples of silence up to the given output buffer's capacity
+//
+// Caller must hold mTimedBufferQueueLock
+void AudioFlinger::PlaybackThread::TimedTrack::timedYieldSilence(
+    uint32_t numFrames, AudioBufferProvider::Buffer* buffer) {
+
+    // lazily allocate a buffer filled with silence
+    if (mTimedSilenceBufferSize < numFrames * mCblk->frameSize) {
+        delete [] mTimedSilenceBuffer;
+        mTimedSilenceBufferSize = numFrames * mCblk->frameSize;
+        mTimedSilenceBuffer = new uint8_t[mTimedSilenceBufferSize];
+        memset(mTimedSilenceBuffer, 0, mTimedSilenceBufferSize);
+    }
+
+    buffer->raw = mTimedSilenceBuffer;
+    size_t framesRequested = buffer->frameCount;
+    buffer->frameCount = min(numFrames, framesRequested);
+
+    mTimedAudioOutputOnTime = false;
+}
+
+void AudioFlinger::PlaybackThread::TimedTrack::releaseBuffer(
+    AudioBufferProvider::Buffer* buffer) {
+
+    Mutex::Autolock _l(mTimedBufferQueueLock);
+
+    // If the buffer which was just released is part of the buffer at the head
+    // of the queue, be sure to update the amt of the buffer which has been
+    // consumed.  If the buffer being returned is not part of the head of the
+    // queue, its either because the buffer is part of the silence buffer, or
+    // because the head of the timed queue was trimmed after the mixer called
+    // getNextBuffer but before the mixer called releaseBuffer.
+    if ((buffer->raw != mTimedSilenceBuffer) && mTimedBufferQueue.size()) {
+        TimedBuffer& head = mTimedBufferQueue.editItemAt(0);
+
+        void* start = head.buffer()->pointer();
+        void* end   = head.buffer()->pointer() + head.buffer()->size();
+
+        if ((buffer->raw >= start) && (buffer->raw <= end)) {
+            head.setPosition(head.position() +
+                    (buffer->frameCount * mCblk->frameSize));
+            if (static_cast<size_t>(head.position()) >= head.buffer()->size()) {
+                mTimedBufferQueue.removeAt(0);
+            }
+        }
+    }
+
+    buffer->raw = 0;
+    buffer->frameCount = 0;
+}
+
+uint32_t AudioFlinger::PlaybackThread::TimedTrack::framesReady() const {
+    Mutex::Autolock _l(mTimedBufferQueueLock);
+
+    uint32_t frames = 0;
+    for (size_t i = 0; i < mTimedBufferQueue.size(); i++) {
+        const TimedBuffer& tb = mTimedBufferQueue[i];
+        frames += (tb.buffer()->size() - tb.position())  / mCblk->frameSize;
+    }
+
+    return frames;
+}
+
+AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer()
+        : mPTS(0), mPosition(0) {}
+
+AudioFlinger::PlaybackThread::TimedTrack::TimedBuffer::TimedBuffer(
+    const sp<IMemory>& buffer, int64_t pts)
+        : mBuffer(buffer), mPTS(pts), mPosition(0) {}
+
 // ----------------------------------------------------------------------------
 
 // RecordTrack constructor must be called with AudioFlinger::mLock held
@@ -3680,7 +4192,7 @@
     }
 }
 
-status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts)
 {
     audio_track_cblk_t* cblk = this->cblk();
     uint32_t framesAvail;
@@ -3985,10 +4497,9 @@
 void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue()
 {
     size_t size = mBufferQueue.size();
-    Buffer *pBuffer;
 
     for (size_t i = 0; i < size; i++) {
-        pBuffer = mBufferQueue.itemAt(i);
+        Buffer *pBuffer = mBufferQueue.itemAt(i);
         delete [] pBuffer->mBuffer;
         delete pBuffer;
     }
@@ -4002,7 +4513,8 @@
         mAudioFlinger(audioFlinger),
         // FIXME should be a "k" constant not hard-coded, in .h or ro. property, see 4 lines below
         mMemoryDealer(new MemoryDealer(1024*1024, "AudioFlinger::Client")),
-        mPid(pid)
+        mPid(pid),
+        mTimedTrackCount(0)
 {
     // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
 }
@@ -4018,6 +4530,31 @@
     return mMemoryDealer;
 }
 
+// Reserve one of the limited slots for a timed audio track associated
+// with this client
+bool AudioFlinger::Client::reserveTimedTrack()
+{
+    const int kMaxTimedTracksPerClient = 4;
+
+    Mutex::Autolock _l(mTimedTrackLock);
+
+    if (mTimedTrackCount >= kMaxTimedTracksPerClient) {
+        ALOGW("can not create timed track - pid %d has exceeded the limit",
+             mPid);
+        return false;
+    }
+
+    mTimedTrackCount++;
+    return true;
+}
+
+// Release a slot for a timed audio track
+void AudioFlinger::Client::releaseTimedTrack()
+{
+    Mutex::Autolock _l(mTimedTrackLock);
+    mTimedTrackCount--;
+}
+
 // ----------------------------------------------------------------------------
 
 AudioFlinger::NotificationClient::NotificationClient(const sp<AudioFlinger>& audioFlinger,
@@ -4034,9 +4571,7 @@
 void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who)
 {
     sp<NotificationClient> keep(this);
-    {
-        mAudioFlinger->removeNotificationClient(mPid);
-    }
+    mAudioFlinger->removeNotificationClient(mPid);
 }
 
 // ----------------------------------------------------------------------------
@@ -4084,6 +4619,38 @@
     return mTrack->attachAuxEffect(EffectId);
 }
 
+status_t AudioFlinger::TrackHandle::allocateTimedBuffer(size_t size,
+                                                         sp<IMemory>* buffer) {
+    if (!mTrack->isTimedTrack())
+        return INVALID_OPERATION;
+
+    PlaybackThread::TimedTrack* tt =
+            reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
+    return tt->allocateTimedBuffer(size, buffer);
+}
+
+status_t AudioFlinger::TrackHandle::queueTimedBuffer(const sp<IMemory>& buffer,
+                                                     int64_t pts) {
+    if (!mTrack->isTimedTrack())
+        return INVALID_OPERATION;
+
+    PlaybackThread::TimedTrack* tt =
+            reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
+    return tt->queueTimedBuffer(buffer, pts);
+}
+
+status_t AudioFlinger::TrackHandle::setMediaTimeTransform(
+    const LinearTransform& xform, int target) {
+
+    if (!mTrack->isTimedTrack())
+        return INVALID_OPERATION;
+
+    PlaybackThread::TimedTrack* tt =
+            reinterpret_cast<PlaybackThread::TimedTrack*>(mTrack.get());
+    return tt->setMediaTimeTransform(
+        xform, static_cast<TimedAudioTrack::TargetTimeline>(target));
+}
+
 status_t AudioFlinger::TrackHandle::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -4313,7 +4880,8 @@
             }
 
             buffer.frameCount = mFrameCount;
-            if (CC_LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
+            if (CC_LIKELY(mActiveTrack->getNextBuffer(
+                    &buffer, AudioBufferProvider::kInvalidPTS) == NO_ERROR)) {
                 size_t framesOut = buffer.frameCount;
                 if (mResampler == NULL) {
                     // no resampling
@@ -4591,7 +5159,7 @@
     return NO_ERROR;
 }
 
-status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer)
+status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer* buffer, int64_t pts)
 {
     size_t framesReq = buffer->frameCount;
     size_t framesReady = mFrameCount - mRsmpInIndex;
@@ -4979,8 +5547,7 @@
                 }
             }
         }
-        void *param2 = NULL;
-        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2);
+        audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, NULL);
         mPlaybackThreads.removeItem(output);
     }
     thread->exit();
@@ -5124,8 +5691,7 @@
         }
 
         ALOGV("closeInput() %d", input);
-        void *param2 = NULL;
-        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, param2);
+        audioConfigChanged_l(AudioSystem::INPUT_CLOSED, input, NULL);
         mRecordThreads.removeItem(input);
     }
     thread->exit();
@@ -5157,8 +5723,7 @@
 
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
         PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
-        if (thread != dstThread &&
-            thread->type() != ThreadBase::DIRECT) {
+        if (thread != dstThread && thread->type() != ThreadBase::DIRECT) {
             MixerThread *srcThread = (MixerThread *)thread;
             srcThread->setStreamValid(stream, false);
             srcThread->invalidateTracks(stream);
@@ -5281,33 +5846,20 @@
 // checkPlaybackThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::PlaybackThread *AudioFlinger::checkPlaybackThread_l(audio_io_handle_t output) const
 {
-    PlaybackThread *thread = NULL;
-    if (mPlaybackThreads.indexOfKey(output) >= 0) {
-        thread = (PlaybackThread *)mPlaybackThreads.valueFor(output).get();
-    }
-    return thread;
+    return mPlaybackThreads.valueFor(output).get();
 }
 
 // checkMixerThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(audio_io_handle_t output) const
 {
     PlaybackThread *thread = checkPlaybackThread_l(output);
-    if (thread != NULL) {
-        if (thread->type() == ThreadBase::DIRECT) {
-            thread = NULL;
-        }
-    }
-    return (MixerThread *)thread;
+    return thread != NULL && thread->type() != ThreadBase::DIRECT ? (MixerThread *) thread : NULL;
 }
 
 // checkRecordThread_l() must be called with AudioFlinger::mLock held
 AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(audio_io_handle_t input) const
 {
-    RecordThread *thread = NULL;
-    if (mRecordThreads.indexOfKey(input) >= 0) {
-        thread = (RecordThread *)mRecordThreads.valueFor(input).get();
-    }
-    return thread;
+    return mRecordThreads.valueFor(input).get();
 }
 
 uint32_t AudioFlinger::nextUniqueId()
@@ -5670,10 +6222,7 @@
         goto Exit;
     }
     // Only Pre processor effects are allowed on input threads and only on input threads
-    if ((mType == RECORD &&
-            (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) ||
-            (mType != RECORD &&
-                    (desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
+    if ((mType == RECORD) != ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
         ALOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d",
                 desc->name, desc->flags, mType);
         lStatus = BAD_VALUE;
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index aa0b8f8..50712cf 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -22,11 +22,14 @@
 #include <sys/types.h>
 #include <limits.h>
 
+#include <common_time/cc_helper.h>
+
 #include <media/IAudioFlinger.h>
 #include <media/IAudioFlingerClient.h>
 #include <media/IAudioTrack.h>
 #include <media/IAudioRecord.h>
 #include <media/AudioSystem.h>
+#include <media/AudioTrack.h>
 
 #include <utils/Atomic.h>
 #include <utils/Errors.h>
@@ -55,7 +58,7 @@
 
 // ----------------------------------------------------------------------------
 
-static const nsecs_t kStandbyTimeInNsecs = seconds(3);
+static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
 
 class AudioFlinger :
     public BinderService<AudioFlinger>,
@@ -78,6 +81,7 @@
                                 uint32_t flags,
                                 const sp<IMemory>& sharedBuffer,
                                 audio_io_handle_t output,
+                                bool isTimed,
                                 int *sessionId,
                                 status_t *status);
 
@@ -102,6 +106,7 @@
     virtual     status_t    setMasterMute(bool muted);
 
     virtual     float       masterVolume() const;
+    virtual     float       masterVolumeSW() const;
     virtual     bool        masterMute() const;
 
     virtual     status_t    setStreamVolume(audio_stream_type_t stream, float value,
@@ -206,6 +211,8 @@
     audio_hw_device_t*      findSuitableHwDev_l(uint32_t devices);
     void                    purgeStaleEffects_l();
 
+    static nsecs_t          mStandbyTimeInNsecs;
+
     // Internal dump utilites.
     status_t dumpPermissionDenial(int fd, const Vector<String16>& args);
     status_t dumpClients(int fd, const Vector<String16>& args);
@@ -220,12 +227,18 @@
         pid_t               pid() const { return mPid; }
         sp<AudioFlinger>    audioFlinger() const { return mAudioFlinger; }
 
+        bool reserveTimedTrack();
+        void releaseTimedTrack();
+
     private:
                             Client(const Client&);
                             Client& operator = (const Client&);
         const sp<AudioFlinger> mAudioFlinger;
         const sp<MemoryDealer> mMemoryDealer;
         const pid_t         mPid;
+
+        Mutex               mTimedTrackLock;
+        int                 mTimedTrackCount;
     };
 
     // --- Notification Client ---
@@ -333,7 +346,9 @@
                                 TrackBase(const TrackBase&);
                                 TrackBase& operator = (const TrackBase&);
 
-            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer) = 0;
+            virtual status_t getNextBuffer(
+                AudioBufferProvider::Buffer* buffer,
+                int64_t pts) = 0;
             virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
 
             audio_format_t format() const {
@@ -609,7 +624,6 @@
                     int16_t     *mainBuffer() const { return mMainBuffer; }
                     int         auxEffectId() const { return mAuxEffectId; }
 
-
         protected:
             friend class ThreadBase;
             friend class TrackHandle;
@@ -620,7 +634,11 @@
                                 Track(const Track&);
                                 Track& operator = (const Track&);
 
-            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+            virtual status_t getNextBuffer(
+                AudioBufferProvider::Buffer* buffer,
+                int64_t pts);
+            virtual uint32_t framesReady() const;
+
             bool isMuted() const { return mMute; }
             bool isPausing() const {
                 return mState == PAUSING;
@@ -636,6 +654,8 @@
                 return (mStreamType == AUDIO_STREAM_CNT);
             }
 
+            virtual bool isTimedTrack() const { return false; }
+
             // we don't really need a lock for these
             volatile bool       mMute;
             // FILLED state is used for suppressing volume ramp at begin of playing
@@ -652,6 +672,79 @@
             bool                mHasVolumeController;
         };  // end of Track
 
+        class TimedTrack : public Track {
+          public:
+            static sp<TimedTrack> create(const wp<ThreadBase>& thread,
+                                         const sp<Client>& client,
+                                         audio_stream_type_t streamType,
+                                         uint32_t sampleRate,
+                                         audio_format_t format,
+                                         uint32_t channelMask,
+                                         int frameCount,
+                                         const sp<IMemory>& sharedBuffer,
+                                         int sessionId);
+            ~TimedTrack();
+
+            class TimedBuffer {
+              public:
+                TimedBuffer();
+                TimedBuffer(const sp<IMemory>& buffer, int64_t pts);
+                const sp<IMemory>& buffer() const { return mBuffer; }
+                int64_t pts() const { return mPTS; }
+                int position() const { return mPosition; }
+                void setPosition(int pos) { mPosition = pos; }
+              private:
+                sp<IMemory> mBuffer;
+                int64_t mPTS;
+                int mPosition;
+            };
+
+            virtual bool isTimedTrack() const { return true; }
+
+            virtual uint32_t framesReady() const;
+
+            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer,
+                                           int64_t pts);
+            virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
+            void timedYieldSamples(AudioBufferProvider::Buffer* buffer);
+            void timedYieldSilence(uint32_t numFrames,
+                                   AudioBufferProvider::Buffer* buffer);
+
+            status_t    allocateTimedBuffer(size_t size,
+                                            sp<IMemory>* buffer);
+            status_t    queueTimedBuffer(const sp<IMemory>& buffer,
+                                         int64_t pts);
+            status_t    setMediaTimeTransform(const LinearTransform& xform,
+                                              TimedAudioTrack::TargetTimeline target);
+            void        trimTimedBufferQueue_l();
+
+          private:
+            TimedTrack(const wp<ThreadBase>& thread,
+                       const sp<Client>& client,
+                       audio_stream_type_t streamType,
+                       uint32_t sampleRate,
+                       audio_format_t format,
+                       uint32_t channelMask,
+                       int frameCount,
+                       const sp<IMemory>& sharedBuffer,
+                       int sessionId);
+
+            uint64_t            mLocalTimeFreq;
+            LinearTransform     mLocalTimeToSampleTransform;
+            sp<MemoryDealer>    mTimedMemoryDealer;
+            Vector<TimedBuffer> mTimedBufferQueue;
+            uint8_t*            mTimedSilenceBuffer;
+            uint32_t            mTimedSilenceBufferSize;
+            mutable Mutex       mTimedBufferQueueLock;
+            bool                mTimedAudioOutputOnTime;
+            CCHelper            mCCHelper;
+
+            Mutex               mMediaTimeTransformLock;
+            LinearTransform     mMediaTimeTransform;
+            bool                mMediaTimeTransformValid;
+            TimedAudioTrack::TargetTimeline mMediaTimeTransformTarget;
+        };
+
 
         // playback track
         class OutputTrack : public Track {
@@ -673,7 +766,7 @@
             virtual status_t    start(pid_t tid);
             virtual void        stop();
                     bool        write(int16_t* data, uint32_t frames);
-                    bool        bufferQueueEmpty() const { return (mBufferQueue.size() == 0) ? true : false; }
+                    bool        bufferQueueEmpty() const { return mBufferQueue.size() == 0; }
                     bool        isActive() const { return mActive; }
             const wp<ThreadBase>& thread() const { return mThread; }
 
@@ -726,6 +819,7 @@
                                     int frameCount,
                                     const sp<IMemory>& sharedBuffer,
                                     int sessionId,
+                                    bool isTimed,
                                     status_t *status);
 
                     AudioStreamOut* getOutput() const;
@@ -900,8 +994,8 @@
               uint32_t nextUniqueId();
 
               status_t moveEffectChain_l(int sessionId,
-                                     AudioFlinger::PlaybackThread *srcThread,
-                                     AudioFlinger::PlaybackThread *dstThread,
+                                     PlaybackThread *srcThread,
+                                     PlaybackThread *dstThread,
                                      bool reRegister);
               PlaybackThread *primaryPlaybackThread_l();
               uint32_t primaryOutputDevice_l();
@@ -920,6 +1014,12 @@
         virtual void        mute(bool);
         virtual void        pause();
         virtual status_t    attachAuxEffect(int effectId);
+        virtual status_t    allocateTimedBuffer(size_t size,
+                                                sp<IMemory>* buffer);
+        virtual status_t    queueTimedBuffer(const sp<IMemory>& buffer,
+                                             int64_t pts);
+        virtual status_t    setMediaTimeTransform(const LinearTransform& xform,
+                                                  int target);
         virtual status_t onTransact(
             uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
     private:
@@ -967,7 +1067,9 @@
                                 RecordTrack(const RecordTrack&);
                                 RecordTrack& operator = (const RecordTrack&);
 
-            virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
+            virtual status_t getNextBuffer(
+                AudioBufferProvider::Buffer* buffer,
+                int64_t pts);
 
             bool                mOverflow;
         };
@@ -1004,7 +1106,8 @@
                 AudioStreamIn* clearInput();
                 virtual audio_stream_t* stream();
 
-        virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer);
+        virtual status_t    getNextBuffer(AudioBufferProvider::Buffer* buffer,
+                                          int64_t pts);
         virtual void        releaseBuffer(AudioBufferProvider::Buffer* buffer);
         virtual bool        checkForNewParameters_l();
         virtual String8     getParameters(const String8& keys);
@@ -1401,6 +1504,28 @@
     friend class RecordThread;
     friend class PlaybackThread;
 
+    enum master_volume_support {
+        // MVS_NONE:
+        // Audio HAL has no support for master volume, either setting or
+        // getting.  All master volume control must be implemented in SW by the
+        // AudioFlinger mixing core.
+        MVS_NONE,
+
+        // MVS_SETONLY:
+        // Audio HAL has support for setting master volume, but not for getting
+        // master volume (original HAL design did not include a getter).
+        // AudioFlinger needs to keep track of the last set master volume in
+        // addition to needing to set an initial, default, master volume at HAL
+        // load time.
+        MVS_SETONLY,
+
+        // MVS_FULL:
+        // Audio HAL has support both for setting and getting master volume.
+        // AudioFlinger should send all set and get master volume requests
+        // directly to the HAL.
+        MVS_FULL,
+    };
+
     mutable     Mutex                               mLock;
 
                 DefaultKeyedVector< pid_t, wp<Client> >     mClients;   // see ~Client()
@@ -1429,6 +1554,7 @@
         AUDIO_SET_VOICE_VOLUME,
         AUDIO_SET_PARAMETER,
         AUDIO_HW_GET_INPUT_BUFFER_SIZE,
+        AUDIO_HW_GET_MASTER_VOLUME,
     };
 
     mutable     hardware_call_state                 mHardwareStatus;    // for dump only
@@ -1439,6 +1565,8 @@
 
                 // both are protected by mLock
                 float                               mMasterVolume;
+                float                               mMasterVolumeSW;
+                master_volume_support               mMasterVolumeSupportLvl;
                 bool                                mMasterMute;
 
                 DefaultKeyedVector< audio_io_handle_t, sp<RecordThread> >    mRecordThreads;
@@ -1451,7 +1579,8 @@
                 // protected by mLock
                 Vector<AudioSessionRef*> mAudioSessionRefs;
 
-                float       masterVolume_l() const  { return mMasterVolume; }
+                float       masterVolume_l() const;
+                float       masterVolumeSW_l() const  { return mMasterVolumeSW; }
                 bool        masterMute_l() const    { return mMasterMute; }
 
 private:
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index cb7678b..020d62a 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -33,6 +33,8 @@
 #include <system/audio.h>
 
 #include <audio_utils/primitives.h>
+#include <common_time/local_clock.h>
+#include <common_time/cc_helper.h>
 
 #include "AudioMixer.h"
 
@@ -45,6 +47,9 @@
 {
     // AudioMixer is not yet capable of multi-channel beyond stereo
     assert(2 == MAX_NUM_CHANNELS);
+    
+    LocalClock lc;
+
     mState.enabledTracks= 0;
     mState.needsChanged = 0;
     mState.frameCount   = frameCount;
@@ -80,6 +85,7 @@
         t->sampleRate = mSampleRate;
         t->mainBuffer = NULL;
         t->auxBuffer = NULL;
+        t->localTimeFreq = lc.getLocalFreq();
         t++;
     }
 }
@@ -251,6 +257,7 @@
             }
             break;
         case AUXLEVEL:
+            //assert(0 <= valueInt && valueInt <= MAX_GAIN_INT);
             if (track.auxLevel != valueInt) {
                 ALOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
                 track.prevAuxLevel = track.auxLevel << 16;
@@ -289,6 +296,7 @@
             if (resampler == NULL) {
                 resampler = AudioResampler::create(
                         format, channelCount, devSampleRate);
+                resampler->setLocalTimeFreq(localTimeFreq);
             }
             return true;
         }
@@ -333,13 +341,13 @@
 
 
 
-void AudioMixer::process()
+void AudioMixer::process(int64_t pts)
 {
-    mState.hook(&mState);
+    mState.hook(&mState, pts);
 }
 
 
-void AudioMixer::process__validate(state_t* state)
+void AudioMixer::process__validate(state_t* state, int64_t pts)
 {
     ALOGW_IF(!state->needsChanged,
         "in process__validate() but nothing's invalid");
@@ -443,7 +451,7 @@
         countActiveTracks, state->enabledTracks,
         all16BitsStereoNoResample, resampling, volumeRamp);
 
-    state->hook(state);
+   state->hook(state, pts);
 
     // Now that the volume ramp has been done, set optimal state and
     // track hooks for subsequent mixer process
@@ -549,7 +557,7 @@
     }
     t->prevVolume[0] = vl;
     t->prevVolume[1] = vr;
-    t->adjustVolumeRamp((aux != NULL));
+    t->adjustVolumeRamp(aux != NULL);
 }
 
 void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
@@ -558,7 +566,7 @@
     const int16_t vr = t->volume[1];
 
     if (CC_UNLIKELY(aux != NULL)) {
-        const int16_t va = (int16_t)t->auxLevel;
+        const int16_t va = t->auxLevel;
         do {
             int16_t l = (int16_t)(*temp++ >> 12);
             int16_t r = (int16_t)(*temp++ >> 12);
@@ -757,7 +765,7 @@
 }
 
 // no-op case
-void AudioMixer::process__nop(state_t* state)
+void AudioMixer::process__nop(state_t* state, int64_t pts)
 {
     uint32_t e0 = state->enabledTracks;
     size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
@@ -787,7 +795,9 @@
             size_t outFrames = state->frameCount;
             while (outFrames) {
                 t1.buffer.frameCount = outFrames;
-                t1.bufferProvider->getNextBuffer(&t1.buffer);
+                int64_t outputPTS = calculateOutputPTS(
+                    t1, pts, state->frameCount - outFrames);
+                t1.bufferProvider->getNextBuffer(&t1.buffer, outputPTS);
                 if (t1.buffer.raw == NULL) break;
                 outFrames -= t1.buffer.frameCount;
                 t1.bufferProvider->releaseBuffer(&t1.buffer);
@@ -797,7 +807,7 @@
 }
 
 // generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state)
+void AudioMixer::process__genericNoResampling(state_t* state, int64_t pts)
 {
     int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
 
@@ -809,7 +819,7 @@
         e0 &= ~(1<<i);
         track_t& t = state->tracks[i];
         t.buffer.frameCount = state->frameCount;
-        t.bufferProvider->getNextBuffer(&t.buffer);
+        t.bufferProvider->getNextBuffer(&t.buffer, pts);
         t.frameCount = t.buffer.frameCount;
         t.in = t.buffer.raw;
         // t.in == NULL can happen if the track was flushed just after having
@@ -853,7 +863,7 @@
                 while (outFrames) {
                     size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
                     if (inFrames) {
-                        (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
+                        t.hook(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
                         t.frameCount -= inFrames;
                         outFrames -= inFrames;
                         if (CC_UNLIKELY(aux != NULL)) {
@@ -863,7 +873,9 @@
                     if (t.frameCount == 0 && outFrames) {
                         t.bufferProvider->releaseBuffer(&t.buffer);
                         t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
-                        t.bufferProvider->getNextBuffer(&t.buffer);
+                        int64_t outputPTS = calculateOutputPTS(
+                            t, pts, numFrames + (BLOCKSIZE - outFrames));
+                        t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
                         t.in = t.buffer.raw;
                         if (t.in == NULL) {
                             enabledTracks &= ~(1<<i);
@@ -892,7 +904,7 @@
 
 
 // generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state)
+void AudioMixer::process__genericResampling(state_t* state, int64_t pts)
 {
     // this const just means that local variable outTemp doesn't change
     int32_t* const outTemp = state->outputTemp;
@@ -932,14 +944,16 @@
             // acquire/release the buffers because it's done by
             // the resampler.
             if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
-                (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
+                t.resampler->setPTS(pts);
+                t.hook(&t, outTemp, numFrames, state->resampleTemp, aux);
             } else {
 
                 size_t outFrames = 0;
 
                 while (outFrames < numFrames) {
                     t.buffer.frameCount = numFrames - outFrames;
-                    t.bufferProvider->getNextBuffer(&t.buffer);
+                    int64_t outputPTS = calculateOutputPTS(t, pts, outFrames);
+                    t.bufferProvider->getNextBuffer(&t.buffer, outputPTS);
                     t.in = t.buffer.raw;
                     // t.in == NULL can happen if the track was flushed just after having
                     // been enabled for mixing.
@@ -948,7 +962,7 @@
                     if (CC_UNLIKELY(aux != NULL)) {
                         aux += outFrames;
                     }
-                    (t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
+                    t.hook(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
                     outFrames += t.buffer.frameCount;
                     t.bufferProvider->releaseBuffer(&t.buffer);
                 }
@@ -959,7 +973,8 @@
 }
 
 // one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
+void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state,
+                                                           int64_t pts)
 {
     // This method is only called when state->enabledTracks has exactly
     // one bit set.  The asserts below would verify this, but are commented out
@@ -979,7 +994,8 @@
     const uint32_t vrl = t.volumeRL;
     while (numFrames) {
         b.frameCount = numFrames;
-        t.bufferProvider->getNextBuffer(&b);
+        int64_t outputPTS = calculateOutputPTS(t, pts, out - t.mainBuffer);
+        t.bufferProvider->getNextBuffer(&b, outputPTS);
         const int16_t *in = b.i16;
 
         // in == NULL can happen if the track was flushed just after having
@@ -1023,7 +1039,8 @@
 // 2 tracks is also a common case
 // NEVER used in current implementation of process__validate()
 // only use if the 2 tracks have the same output buffer
-void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)
+void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state,
+                                                            int64_t pts)
 {
     int i;
     uint32_t en = state->enabledTracks;
@@ -1057,7 +1074,9 @@
 
         if (frameCount0 == 0) {
             b0.frameCount = numFrames;
-            t0.bufferProvider->getNextBuffer(&b0);
+            int64_t outputPTS = calculateOutputPTS(t0, pts,
+                                                   out - t0.mainBuffer);
+            t0.bufferProvider->getNextBuffer(&b0, outputPTS);
             if (b0.i16 == NULL) {
                 if (buff == NULL) {
                     buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
@@ -1071,7 +1090,9 @@
         }
         if (frameCount1 == 0) {
             b1.frameCount = numFrames;
-            t1.bufferProvider->getNextBuffer(&b1);
+            int64_t outputPTS = calculateOutputPTS(t1, pts,
+                                                   out - t0.mainBuffer);
+            t1.bufferProvider->getNextBuffer(&b1, outputPTS);
             if (b1.i16 == NULL) {
                 if (buff == NULL) {
                     buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
@@ -1117,5 +1138,14 @@
 }
 #endif
 
+int64_t AudioMixer::calculateOutputPTS(const track_t& t, int64_t basePTS,
+                                       int outputFrameIndex)
+{
+    if (AudioBufferProvider::kInvalidPTS == basePTS)
+        return AudioBufferProvider::kInvalidPTS;
+
+    return basePTS + ((outputFrameIndex * t.localTimeFreq) / t.sampleRate);
+}
+
 // ----------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/audioflinger/AudioMixer.h b/services/audioflinger/AudioMixer.h
index c956918..b210212 100644
--- a/services/audioflinger/AudioMixer.h
+++ b/services/audioflinger/AudioMixer.h
@@ -79,7 +79,7 @@
     void        setParameter(int name, int target, int param, void *value);
 
     void        setBufferProvider(int name, AudioBufferProvider* bufferProvider);
-    void        process();
+    void        process(int64_t pts);
 
     uint32_t    trackNames() const { return mTrackNames; }
 
@@ -114,7 +114,6 @@
     struct state_t;
     struct track_t;
 
-    typedef void (*mix_t)(state_t* state);
     typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
     static const int BLOCKSIZE = 16; // 4 cache lines
 
@@ -128,30 +127,46 @@
 
         int32_t     prevVolume[MAX_NUM_CHANNELS];
 
+        // 16-byte boundary
+
         int32_t     volumeInc[MAX_NUM_CHANNELS];
-        int32_t     auxLevel;
         int32_t     auxInc;
         int32_t     prevAuxLevel;
 
+        // 16-byte boundary
+
+        int16_t     auxLevel;       // 0 <= auxLevel <= MAX_GAIN_INT, but signed for mul performance
         uint16_t    frameCount;
 
-        uint8_t     channelCount : 4;
-        uint8_t     enabled      : 1;
-        uint8_t     reserved0    : 3;
-        uint8_t     format;
-        uint32_t    channelMask;
+        uint8_t     channelCount;   // 1 or 2, redundant with (needs & NEEDS_CHANNEL_COUNT__MASK)
+        uint8_t     format;         // always 16
+        uint16_t    enabled;        // actually bool
+        uint32_t    channelMask;    // currently under-used
 
         AudioBufferProvider*                bufferProvider;
-        mutable AudioBufferProvider::Buffer buffer;
+
+        // 16-byte boundary
+
+        mutable AudioBufferProvider::Buffer buffer; // 8 bytes
 
         hook_t      hook;
         const void* in;             // current location in buffer
 
+        // 16-byte boundary
+
         AudioResampler*     resampler;
         uint32_t            sampleRate;
         int32_t*           mainBuffer;
         int32_t*           auxBuffer;
 
+        // 16-byte boundary
+
+        uint64_t    localTimeFreq;
+
+        int64_t     padding;
+
+        // 16-byte boundary
+
         bool        setResampler(uint32_t sampleRate, uint32_t devSampleRate);
         bool        doesResample() const { return resampler != NULL; }
         void        resetResampler() { if (resampler != NULL) resampler->reset(); }
@@ -165,7 +180,7 @@
         uint32_t        enabledTracks;
         uint32_t        needsChanged;
         size_t          frameCount;
-        mix_t           hook;
+        void            (*hook)(state_t* state, int64_t pts);   // one of process__*, never NULL
         int32_t         *outputTemp;
         int32_t         *resampleTemp;
         int32_t         reserved[2];
@@ -187,14 +202,19 @@
     static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
     static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
 
-    static void process__validate(state_t* state);
-    static void process__nop(state_t* state);
-    static void process__genericNoResampling(state_t* state);
-    static void process__genericResampling(state_t* state);
-    static void process__OneTrack16BitsStereoNoResampling(state_t* state);
+    static void process__validate(state_t* state, int64_t pts);
+    static void process__nop(state_t* state, int64_t pts);
+    static void process__genericNoResampling(state_t* state, int64_t pts);
+    static void process__genericResampling(state_t* state, int64_t pts);
+    static void process__OneTrack16BitsStereoNoResampling(state_t* state,
+                                                          int64_t pts);
 #if 0
-    static void process__TwoTracks16BitsStereoNoResampling(state_t* state);
+    static void process__TwoTracks16BitsStereoNoResampling(state_t* state,
+                                                           int64_t pts);
 #endif
+
+    static int64_t calculateOutputPTS(const track_t& t, int64_t basePTS,
+                                      int outputFrameIndex);
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 041b5a8..987b039 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -116,19 +116,7 @@
 
     // release audio pre processing resources
     for (size_t i = 0; i < mInputSources.size(); i++) {
-        InputSourceDesc *source = mInputSources.valueAt(i);
-        Vector <EffectDesc *> effects = source->mEffects;
-        for (size_t j = 0; j < effects.size(); j++) {
-            delete effects[j]->mName;
-            Vector <effect_param_t *> params = effects[j]->mParams;
-            for (size_t k = 0; k < params.size(); k++) {
-                delete params[k];
-            }
-            params.clear();
-            delete effects[j];
-        }
-        effects.clear();
-        delete source;
+        delete mInputSources.valueAt(i);
     }
     mInputSources.clear();
 
@@ -616,8 +604,7 @@
 {
     Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects;
     for (size_t i = 0; i < fxVector.size(); i++) {
-        sp<AudioEffect> fx = fxVector.itemAt(i);
-        fx->setEnabled(enabled);
+        fxVector.itemAt(i)->setEnabled(enabled);
     }
 }
 
@@ -1243,7 +1230,7 @@
             node = node->next;
             continue;
         }
-        EffectDesc *effect = new EffectDesc(*effects[i]);
+        EffectDesc *effect = new EffectDesc(*effects[i]);   // deep copy
         loadEffectParameters(node, effect->mParams);
         ALOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow);
         source->mEffects.add(effect);
@@ -1294,11 +1281,7 @@
         ALOGW("loadEffect() invalid uuid %s", node->value);
         return NULL;
     }
-    EffectDesc *effect = new EffectDesc();
-    effect->mName = strdup(root->name);
-    memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t));
-
-    return effect;
+    return new EffectDesc(root->name, uuid);
 }
 
 status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index fdaf576..679fd30 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -233,8 +233,33 @@
 
     class EffectDesc {
     public:
-        EffectDesc() {}
-        virtual ~EffectDesc() {}
+        EffectDesc(const char *name, const effect_uuid_t& uuid) :
+                        mName(strdup(name)),
+                        mUuid(uuid) { }
+        EffectDesc(const EffectDesc& orig) :
+                        mName(strdup(orig.mName)),
+                        mUuid(orig.mUuid) {
+                            // deep copy mParams
+                            for (size_t k = 0; k < orig.mParams.size(); k++) {
+                                effect_param_t *origParam = orig.mParams[k];
+                                // psize and vsize are rounded up to an int boundary for allocation
+                                size_t origSize = sizeof(effect_param_t) +
+                                                  ((origParam->psize + 3) & ~3) +
+                                                  ((origParam->vsize + 3) & ~3);
+                                effect_param_t *dupParam = (effect_param_t *) malloc(origSize);
+                                memcpy(dupParam, origParam, origSize);
+                                // This works because the param buffer allocation is also done by
+                                // multiples of 4 bytes originally. In theory we should memcpy only
+                                // the actual param size, that is without rounding vsize.
+                                mParams.add(dupParam);
+                            }
+                        }
+        /*virtual*/ ~EffectDesc() {
+            free(mName);
+            for (size_t k = 0; k < mParams.size(); k++) {
+                free(mParams[k]);
+            }
+        }
         char *mName;
         effect_uuid_t mUuid;
         Vector <effect_param_t *> mParams;
@@ -243,7 +268,11 @@
     class InputSourceDesc {
     public:
         InputSourceDesc() {}
-        virtual ~InputSourceDesc() {}
+        /*virtual*/ ~InputSourceDesc() {
+            for (size_t j = 0; j < mEffects.size(); j++) {
+                delete mEffects[j];
+            }
+        }
         Vector <EffectDesc *> mEffects;
     };
 
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 9486b9c..398ba0b 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -122,7 +122,8 @@
         int32_t sampleRate) :
     mBitDepth(bitDepth), mChannelCount(inChannelCount),
             mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
-            mPhaseFraction(0) {
+            mPhaseFraction(0), mLocalTimeFreq(0),
+            mPTS(AudioBufferProvider::kInvalidPTS) {
     // sanity check on format
     if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
         ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
@@ -150,6 +151,23 @@
     mVolume[1] = right;
 }
 
+void AudioResampler::setLocalTimeFreq(uint64_t freq) {
+    mLocalTimeFreq = freq;
+}
+
+void AudioResampler::setPTS(int64_t pts) {
+    mPTS = pts;
+}
+
+int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
+
+    if (mPTS == AudioBufferProvider::kInvalidPTS) {
+        return AudioBufferProvider::kInvalidPTS;
+    } else {
+        return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
+    }
+}
+
 void AudioResampler::reset() {
     mInputIndex = 0;
     mPhaseFraction = 0;
@@ -196,7 +214,8 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&mBuffer);
+            provider->getNextBuffer(&mBuffer,
+                                    calculateOutputPTS(outputIndex / 2));
             if (mBuffer.raw == NULL) {
                 goto resampleStereo16_exit;
             }
@@ -290,7 +309,8 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&mBuffer);
+            provider->getNextBuffer(&mBuffer,
+                                    calculateOutputPTS(outputIndex / 2));
             if (mBuffer.raw == NULL) {
                 mInputIndex = inputIndex;
                 mPhaseFraction = phaseFraction;
diff --git a/services/audioflinger/AudioResampler.h b/services/audioflinger/AudioResampler.h
index c23016e..9deb796 100644
--- a/services/audioflinger/AudioResampler.h
+++ b/services/audioflinger/AudioResampler.h
@@ -49,6 +49,10 @@
     virtual void init() = 0;
     virtual void setSampleRate(int32_t inSampleRate);
     virtual void setVolume(int16_t left, int16_t right);
+    virtual void setLocalTimeFreq(uint64_t freq);
+
+    // set the PTS of the next buffer output by the resampler
+    virtual void setPTS(int64_t pts);
 
     virtual void resample(int32_t* out, size_t outFrameCount,
             AudioBufferProvider* provider) = 0;
@@ -72,6 +76,8 @@
     AudioResampler(const AudioResampler&);
     AudioResampler& operator=(const AudioResampler&);
 
+    int64_t calculateOutputPTS(int outputFrameIndex);
+
     const int32_t mBitDepth;
     const int32_t mChannelCount;
     const int32_t mSampleRate;
@@ -85,6 +91,8 @@
     size_t mInputIndex;
     int32_t mPhaseIncrement;
     uint32_t mPhaseFraction;
+    uint64_t mLocalTimeFreq;
+    int64_t mPTS;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/audioflinger/AudioResamplerCubic.cpp b/services/audioflinger/AudioResamplerCubic.cpp
index c0e760e..18e59e9 100644
--- a/services/audioflinger/AudioResamplerCubic.cpp
+++ b/services/audioflinger/AudioResamplerCubic.cpp
@@ -65,7 +65,7 @@
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
         mBuffer.frameCount = inFrameCount;
-        provider->getNextBuffer(&mBuffer);
+        provider->getNextBuffer(&mBuffer, mPTS);
         if (mBuffer.raw == NULL)
             return;
         // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
@@ -95,7 +95,8 @@
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
                 mBuffer.frameCount = inFrameCount;
-                provider->getNextBuffer(&mBuffer);
+                provider->getNextBuffer(&mBuffer,
+                                        calculateOutputPTS(outputIndex / 2));
                 if (mBuffer.raw == NULL)
                     goto save_state;  // ugly, but efficient
                 in = mBuffer.i16;
@@ -130,7 +131,7 @@
     // fetch first buffer
     if (mBuffer.frameCount == 0) {
         mBuffer.frameCount = inFrameCount;
-        provider->getNextBuffer(&mBuffer);
+        provider->getNextBuffer(&mBuffer, mPTS);
         if (mBuffer.raw == NULL)
             return;
         // ALOGW("New buffer: offset=%p, frames=%d", mBuffer.raw, mBuffer.frameCount);
@@ -160,7 +161,8 @@
                 inputIndex = 0;
                 provider->releaseBuffer(&mBuffer);
                 mBuffer.frameCount = inFrameCount;
-                provider->getNextBuffer(&mBuffer);
+                provider->getNextBuffer(&mBuffer,
+                                        calculateOutputPTS(outputIndex / 2));
                 if (mBuffer.raw == NULL)
                     goto save_state;  // ugly, but efficient
                 // ALOGW("New buffer: offset=%p, frames=%dn", mBuffer.raw, mBuffer.frameCount);
@@ -181,4 +183,3 @@
 // ----------------------------------------------------------------------------
 }
 ; // namespace android
-
diff --git a/services/audioflinger/AudioResamplerSinc.cpp b/services/audioflinger/AudioResamplerSinc.cpp
index 7a27b81..d373c08 100644
--- a/services/audioflinger/AudioResamplerSinc.cpp
+++ b/services/audioflinger/AudioResamplerSinc.cpp
@@ -203,7 +203,8 @@
         // buffer is empty, fetch a new one
         while (mBuffer.frameCount == 0) {
             mBuffer.frameCount = inFrameCount;
-            provider->getNextBuffer(&mBuffer);
+            provider->getNextBuffer(&mBuffer,
+                                    calculateOutputPTS(outputIndex / 2));
             if (mBuffer.raw == NULL) {
                 goto resample_exit;
             }
@@ -354,4 +355,3 @@
 
 // ----------------------------------------------------------------------------
 }; // namespace android
-
diff --git a/services/common_time/Android.mk b/services/common_time/Android.mk
new file mode 100644
index 0000000..e534d49
--- /dev/null
+++ b/services/common_time/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+#
+# common_time_service
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+    common_clock_service.cpp \
+    common_time_config_service.cpp \
+    common_time_server.cpp \
+    common_time_server_api.cpp \
+    common_time_server_packets.cpp \
+    clock_recovery.cpp \
+    common_clock.cpp \
+    main.cpp
+
+# Uncomment to enable vesbose logging and debug service.
+#TIME_SERVICE_DEBUG=true
+ifeq ($(TIME_SERVICE_DEBUG), true)
+LOCAL_SRC_FILES += diag_thread.cpp
+LOCAL_CFLAGS += -DTIME_SERVICE_DEBUG
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libcommon_time_client \
+    libutils
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := common_time
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/common_time/clock_recovery.cpp b/services/common_time/clock_recovery.cpp
new file mode 100644
index 0000000..6c98d32
--- /dev/null
+++ b/services/common_time/clock_recovery.cpp
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define __STDC_LIMIT_MACROS
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+#include <stdint.h>
+
+#include <common_time/local_clock.h>
+#include <assert.h>
+
+#include "clock_recovery.h"
+#include "common_clock.h"
+#ifdef TIME_SERVICE_DEBUG
+#include "diag_thread.h"
+#endif
+
+// Define log macro so we can make LOGV into LOGE when we are exclusively
+// debugging this code.
+#ifdef TIME_SERVICE_DEBUG
+#define LOG_TS ALOGE
+#else
+#define LOG_TS ALOGV
+#endif
+
+namespace android {
+
+ClockRecoveryLoop::ClockRecoveryLoop(LocalClock* local_clock,
+                                     CommonClock* common_clock) {
+    assert(NULL != local_clock);
+    assert(NULL != common_clock);
+
+    local_clock_  = local_clock;
+    common_clock_ = common_clock;
+
+    local_clock_can_slew_ = local_clock_->initCheck() &&
+                           (local_clock_->setLocalSlew(0) == OK);
+
+    reset(true, true);
+
+#ifdef TIME_SERVICE_DEBUG
+    diag_thread_ = new DiagThread(common_clock_, local_clock_);
+    if (diag_thread_ != NULL) {
+        status_t res = diag_thread_->startWorkThread();
+        if (res != OK)
+            ALOGW("Failed to start A@H clock recovery diagnostic thread.");
+    } else
+        ALOGW("Failed to allocate diagnostic thread.");
+#endif
+}
+
+ClockRecoveryLoop::~ClockRecoveryLoop() {
+#ifdef TIME_SERVICE_DEBUG
+    diag_thread_->stopWorkThread();
+#endif
+}
+
+// Constants.
+const float ClockRecoveryLoop::dT = 1.0;
+const float ClockRecoveryLoop::Kc = 1.0f;
+const float ClockRecoveryLoop::Ti = 15.0f;
+const float ClockRecoveryLoop::Tf = 0.05;
+const float ClockRecoveryLoop::bias_Fc = 0.01;
+const float ClockRecoveryLoop::bias_RC = (dT / (2 * 3.14159f * bias_Fc));
+const float ClockRecoveryLoop::bias_Alpha = (dT / (bias_RC + dT));
+const int64_t ClockRecoveryLoop::panic_thresh_ = 50000;
+const int64_t ClockRecoveryLoop::control_thresh_ = 10000;
+const float ClockRecoveryLoop::COmin = -100.0f;
+const float ClockRecoveryLoop::COmax = 100.0f;
+
+void ClockRecoveryLoop::reset(bool position, bool frequency) {
+    Mutex::Autolock lock(&lock_);
+    reset_l(position, frequency);
+}
+
+uint32_t ClockRecoveryLoop::findMinRTTNdx(DisciplineDataPoint* data,
+                                          uint32_t count) {
+    uint32_t min_rtt = 0;
+    for (uint32_t i = 1; i < count; ++i)
+        if (data[min_rtt].rtt > data[i].rtt)
+            min_rtt = i;
+
+    return min_rtt;
+}
+
+bool ClockRecoveryLoop::pushDisciplineEvent(int64_t local_time,
+                                            int64_t nominal_common_time,
+                                            int64_t rtt) {
+    Mutex::Autolock lock(&lock_);
+
+    int64_t local_common_time = 0;
+    common_clock_->localToCommon(local_time, &local_common_time);
+    int64_t raw_delta = nominal_common_time - local_common_time;
+
+#ifdef TIME_SERVICE_DEBUG
+    ALOGE("local=%lld, common=%lld, delta=%lld, rtt=%lld\n",
+         local_common_time, nominal_common_time,
+         raw_delta, rtt);
+#endif
+
+    // If we have not defined a basis for common time, then we need to use these
+    // initial points to do so.  In order to avoid significant initial error
+    // from a particularly bad startup data point, we collect the first N data
+    // points and choose the best of them before moving on.
+    if (!common_clock_->isValid()) {
+        if (startup_filter_wr_ < kStartupFilterSize) {
+            DisciplineDataPoint& d =  startup_filter_data_[startup_filter_wr_];
+            d.local_time = local_time;
+            d.nominal_common_time = nominal_common_time;
+            d.rtt = rtt;
+            startup_filter_wr_++;
+        }
+
+        if (startup_filter_wr_ == kStartupFilterSize) {
+            uint32_t min_rtt = findMinRTTNdx(startup_filter_data_,
+                    kStartupFilterSize);
+
+            common_clock_->setBasis(
+                    startup_filter_data_[min_rtt].local_time,
+                    startup_filter_data_[min_rtt].nominal_common_time);
+        }
+
+        return true;
+    }
+
+    int64_t observed_common;
+    int64_t delta;
+    float delta_f, dCO;
+    int32_t correction_cur;
+
+    if (OK != common_clock_->localToCommon(local_time, &observed_common)) {
+        // Since we just checked to make certain that this conversion was valid,
+        // and no one else in the system should be messing with it, if this
+        // conversion is suddenly invalid, it is a good reason to panic.
+        ALOGE("Failed to convert local time to common time in %s:%d",
+                __PRETTY_FUNCTION__, __LINE__);
+        return false;
+    }
+
+    // Implement a filter which should match NTP filtering behavior when a
+    // client is associated with only one peer of lower stratum.  Basically,
+    // always use the best of the N last data points, where best is defined as
+    // lowest round trip time.  NTP uses an N of 8; we use a value of 6.
+    //
+    // TODO(johngro) : experiment with other filter strategies.  The goal here
+    // is to mitigate the effects of high RTT data points which typically have
+    // large asymmetries in the TX/RX legs.  Downside of the existing NTP
+    // approach (particularly because of the PID controller we are using to
+    // produce the control signal from the filtered data) are that the rate at
+    // which discipline events are actually acted upon becomes irregular and can
+    // become drawn out (the time between actionable event can go way up).  If
+    // the system receives a strong high quality data point, the proportional
+    // component of the controller can produce a strong correction which is left
+    // in place for too long causing overshoot.  In addition, the integral
+    // component of the system currently is an approximation based on the
+    // assumption of a more or less homogeneous sampling of the error.  Its
+    // unclear what the effect of undermining this assumption would be right
+    // now.
+
+    // Two ideas which come to mind immediately would be to...
+    // 1) Keep a history of more data points (32 or so) and ignore data points
+    //    whose RTT is more than a certain number of standard deviations outside
+    //    of the norm.
+    // 2) Eliminate the PID controller portion of this system entirely.
+    //    Instead, move to a system which uses a very wide filter (128 data
+    //    points or more) with a sum-of-least-squares line fitting approach to
+    //    tracking the long term drift.  This would take the place of the I
+    //    component in the current PID controller.  Also use a much more narrow
+    //    outlier-rejector filter (as described in #1) to drive a short term
+    //    correction factor similar to the P component of the PID controller.
+    assert(filter_wr_ < kFilterSize);
+    filter_data_[filter_wr_].local_time           = local_time;
+    filter_data_[filter_wr_].observed_common_time = observed_common;
+    filter_data_[filter_wr_].nominal_common_time  = nominal_common_time;
+    filter_data_[filter_wr_].rtt                  = rtt;
+    filter_data_[filter_wr_].point_used           = false;
+    uint32_t current_point = filter_wr_;
+    filter_wr_ = (filter_wr_ + 1) % kFilterSize;
+    if (!filter_wr_)
+        filter_full_ = true;
+
+    uint32_t scan_end = filter_full_ ? kFilterSize : filter_wr_;
+    uint32_t min_rtt = findMinRTTNdx(filter_data_, scan_end);
+    // We only use packets with low RTTs for control. If the packet RTT
+    // is less than the panic threshold, we can probably eat the jitter with the
+    // control loop. Otherwise, take the packet only if it better than all
+    // of the packets we have in the history. That way we try to track
+    // something, even if it is noisy.
+    if (current_point == min_rtt || rtt < control_thresh_) {
+        delta_f = delta = nominal_common_time - observed_common;
+
+        // Compute the error then clamp to the panic threshold.  If we ever
+        // exceed this amt of error, its time to panic and reset the system.
+        // Given that the error in the measurement of the error could be as
+        // high as the RTT of the data point, we don't actually panic until
+        // the implied error (delta) is greater than the absolute panic
+        // threashold plus the RTT.  IOW - we don't panic until we are
+        // absoluely sure that our best case sync is worse than the absolute
+        // panic threshold.
+        int64_t effective_panic_thresh = panic_thresh_ + rtt;
+        if ((delta > effective_panic_thresh) ||
+            (delta < -effective_panic_thresh)) {
+            // PANIC!!!
+            reset_l(false, true);
+            return false;
+        }
+
+    } else {
+        // We do not have a good packet to look at, but we also do not want to
+        // free-run the clock at some crazy slew rate. So we guess the
+        // trajectory of the clock based on the last controller output and the
+        // estimated bias of our clock against the master.
+        // The net effect of this is that CO == CObias after some extended
+        // period of no feedback.
+        delta_f = last_delta_f_ - dT*(CO - CObias);
+        delta = delta_f;
+    }
+
+    // Velocity form PI control equation.
+    dCO = Kc * (1.0f + dT/Ti) * delta_f - Kc * last_delta_f_;
+    CO += dCO * Tf; // Filter CO by applying gain <1 here.
+
+    // Save error terms for later.
+    last_delta_f_ = delta_f;
+    last_delta_ = delta;
+
+    // Clamp CO to +/- 100ppm.
+    if (CO < COmin)
+        CO = COmin;
+    else if (CO > COmax)
+        CO = COmax;
+
+    // Update the controller bias.
+    CObias = bias_Alpha * CO + (1.0f - bias_Alpha) * lastCObias;
+    lastCObias = CObias;
+
+    // Convert PPM to 16-bit int range. Add some guard band (-0.01) so we
+    // don't get fp weirdness.
+    correction_cur = CO * 327.66;
+
+    // If there was a change in the amt of correction to use, update the
+    // system.
+    if (correction_cur_ != correction_cur) {
+        correction_cur_ = correction_cur;
+        applySlew();
+    }
+
+    LOG_TS("clock_loop %lld %f %f %f %d\n", raw_delta, delta_f, CO, CObias, correction_cur);
+
+#ifdef TIME_SERVICE_DEBUG
+    diag_thread_->pushDisciplineEvent(
+            local_time,
+            observed_common,
+            nominal_common_time,
+            correction_cur,
+            rtt);
+#endif
+
+    return true;
+}
+
+int32_t ClockRecoveryLoop::getLastErrorEstimate() {
+    Mutex::Autolock lock(&lock_);
+
+    if (last_delta_valid_)
+        return last_delta_;
+    else
+        return ICommonClock::kErrorEstimateUnknown;
+}
+
+void ClockRecoveryLoop::reset_l(bool position, bool frequency) {
+    assert(NULL != common_clock_);
+
+    if (position) {
+        common_clock_->resetBasis();
+        startup_filter_wr_ = 0;
+    }
+
+    if (frequency) {
+        last_delta_valid_ = false;
+        last_delta_ = 0;
+        last_delta_f_ = 0.0;
+        correction_cur_ = 0x0;
+        CO = 0.0f;
+        lastCObias = CObias = 0.0f;
+        applySlew();
+    }
+
+    filter_wr_   = 0;
+    filter_full_ = false;
+}
+
+void ClockRecoveryLoop::applySlew() {
+    if (local_clock_can_slew_) {
+        local_clock_->setLocalSlew(correction_cur_);
+    } else {
+        // The SW clock recovery implemented by the common clock class expects
+        // values expressed in PPM. CO is in ppm.
+        common_clock_->setSlew(local_clock_->getLocalTime(), CO);
+    }
+}
+
+}  // namespace android
diff --git a/services/common_time/clock_recovery.h b/services/common_time/clock_recovery.h
new file mode 100644
index 0000000..b7362be
--- /dev/null
+++ b/services/common_time/clock_recovery.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __CLOCK_RECOVERY_H__
+#define __CLOCK_RECOVERY_H__
+
+#include <stdint.h>
+#include <common_time/ICommonClock.h>
+#include <utils/LinearTransform.h>
+#include <utils/threads.h>
+
+#ifdef TIME_SERVICE_DEBUG
+#include "diag_thread.h"
+#endif
+
+namespace android {
+
+class CommonClock;
+class LocalClock;
+
+class ClockRecoveryLoop {
+  public:
+     ClockRecoveryLoop(LocalClock* local_clock, CommonClock* common_clock);
+    ~ClockRecoveryLoop();
+
+    void reset(bool position, bool frequency);
+    bool pushDisciplineEvent(int64_t local_time,
+                             int64_t nominal_common_time,
+                             int64_t data_point_rtt);
+    int32_t getLastErrorEstimate();
+
+  private:
+
+    // Tuned using the "Good Gain" method.
+    // See:
+    // http://techteach.no/publications/books/dynamics_and_control/tuning_pid_controller.pdf
+
+    // Controller period (1Hz for now).
+    static const float dT;
+
+    // Controller gain, positive and unitless. Larger values converge faster,
+    // but can cause instability.
+    static const float Kc;
+
+    // Integral reset time. Smaller values cause loop to track faster, but can
+    // also cause instability.
+    static const float Ti;
+
+    // Controller output filter time constant. Range (0-1). Smaller values make
+    // output smoother, but slow convergence.
+    static const float Tf;
+
+    // Low-pass filter for bias tracker.
+    static const float bias_Fc; // HZ
+    static const float bias_RC; // Computed in constructor.
+    static const float bias_Alpha; // Computed inconstructor.
+
+    // The maximum allowed error (as indicated by a  pushDisciplineEvent) before
+    // we panic.
+    static const int64_t panic_thresh_;
+
+    // The maximum allowed error rtt time for packets to be used for control
+    // feedback, unless the packet is the best in recent memory.
+    static const int64_t control_thresh_;
+
+    typedef struct {
+        int64_t local_time;
+        int64_t observed_common_time;
+        int64_t nominal_common_time;
+        int64_t rtt;
+        bool point_used;
+    } DisciplineDataPoint;
+
+    static uint32_t findMinRTTNdx(DisciplineDataPoint* data, uint32_t count);
+
+    void reset_l(bool position, bool frequency);
+    void applySlew();
+
+    // The local clock HW abstraction we use as the basis for common time.
+    LocalClock* local_clock_;
+    bool local_clock_can_slew_;
+
+    // The common clock we end up controlling along with the lock used to
+    // serialize operations.
+    CommonClock* common_clock_;
+    Mutex lock_;
+
+    // parameters maintained while running and reset during a reset
+    // of the frequency correction.
+    bool    last_delta_valid_;
+    int32_t last_delta_;
+    float last_delta_f_;
+    int32_t integrated_error_;
+    int32_t correction_cur_;
+
+    // Contoller Output.
+    float CO;
+
+    // Bias tracking for trajectory estimation.
+    float CObias;
+    float lastCObias;
+
+    // Controller output bounds. The controller will not try to
+    // slew faster that +/-100ppm offset from center per interation.
+    static const float COmin;
+    static const float COmax;
+
+    // State kept for filtering the discipline data.
+    static const uint32_t kFilterSize = 16;
+    DisciplineDataPoint filter_data_[kFilterSize];
+    uint32_t filter_wr_;
+    bool filter_full_;
+
+    static const uint32_t kStartupFilterSize = 4;
+    DisciplineDataPoint startup_filter_data_[kStartupFilterSize];
+    uint32_t startup_filter_wr_;
+
+#ifdef TIME_SERVICE_DEBUG
+    sp<DiagThread> diag_thread_;
+#endif
+};
+
+}  // namespace android
+
+#endif  // __CLOCK_RECOVERY_H__
diff --git a/services/common_time/common_clock.cpp b/services/common_time/common_clock.cpp
new file mode 100644
index 0000000..c9eb388
--- /dev/null
+++ b/services/common_time/common_clock.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define __STDC_LIMIT_MACROS
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <stdint.h>
+
+#include <utils/Errors.h>
+#include <utils/LinearTransform.h>
+
+#include "common_clock.h"
+
+namespace android {
+
+CommonClock::CommonClock() {
+    cur_slew_        = 0;
+    cur_trans_valid_ = false;
+
+    cur_trans_.a_zero = 0;
+    cur_trans_.b_zero = 0;
+    cur_trans_.a_to_b_numer = local_to_common_freq_numer_ = 1;
+    cur_trans_.a_to_b_denom = local_to_common_freq_denom_ = 1;
+    duration_trans_ = cur_trans_;
+}
+
+bool CommonClock::init(uint64_t local_freq) {
+    Mutex::Autolock lock(&lock_);
+
+    if (!local_freq)
+        return false;
+
+    uint64_t numer = kCommonFreq;
+    uint64_t denom = local_freq;
+
+    LinearTransform::reduce(&numer, &denom);
+    if ((numer > UINT32_MAX) || (denom > UINT32_MAX)) {
+        ALOGE("Overflow in CommonClock::init while trying to reduce %lld/%lld",
+             kCommonFreq, local_freq);
+        return false;
+    }
+
+    cur_trans_.a_to_b_numer = local_to_common_freq_numer_ =
+        static_cast<uint32_t>(numer);
+    cur_trans_.a_to_b_denom = local_to_common_freq_denom_ =
+        static_cast<uint32_t>(denom);
+    duration_trans_ = cur_trans_;
+
+    return true;
+}
+
+status_t CommonClock::localToCommon(int64_t local, int64_t *common_out) const {
+    Mutex::Autolock lock(&lock_);
+
+    if (!cur_trans_valid_)
+        return INVALID_OPERATION;
+
+    if (!cur_trans_.doForwardTransform(local, common_out))
+        return INVALID_OPERATION;
+
+    return OK;
+}
+
+status_t CommonClock::commonToLocal(int64_t common, int64_t *local_out) const {
+    Mutex::Autolock lock(&lock_);
+
+    if (!cur_trans_valid_)
+        return INVALID_OPERATION;
+
+    if (!cur_trans_.doReverseTransform(common, local_out))
+        return INVALID_OPERATION;
+
+    return OK;
+}
+
+int64_t CommonClock::localDurationToCommonDuration(int64_t localDur) const {
+    int64_t ret;
+    duration_trans_.doForwardTransform(localDur, &ret);
+    return ret;
+}
+
+void CommonClock::setBasis(int64_t local, int64_t common) {
+    Mutex::Autolock lock(&lock_);
+
+    cur_trans_.a_zero = local;
+    cur_trans_.b_zero = common;
+    cur_trans_valid_ = true;
+}
+
+void CommonClock::resetBasis() {
+    Mutex::Autolock lock(&lock_);
+
+    cur_trans_.a_zero = 0;
+    cur_trans_.b_zero = 0;
+    cur_trans_valid_ = false;
+}
+
+status_t CommonClock::setSlew(int64_t change_time, int32_t ppm) {
+    Mutex::Autolock lock(&lock_);
+
+    int64_t new_local_basis;
+    int64_t new_common_basis;
+
+    if (cur_trans_valid_) {
+        new_local_basis = change_time;
+        if (!cur_trans_.doForwardTransform(change_time, &new_common_basis)) {
+            ALOGE("Overflow when attempting to set slew rate to %d", ppm);
+            return INVALID_OPERATION;
+        }
+    } else {
+        new_local_basis = 0;
+        new_common_basis = 0;
+    }
+
+    cur_slew_ = ppm;
+    uint32_t n1 = local_to_common_freq_numer_;
+    uint32_t n2 = 1000000 + cur_slew_;
+
+    uint32_t d1 = local_to_common_freq_denom_;
+    uint32_t d2 = 1000000;
+
+    // n1/d1 has already been reduced, no need to do so here.
+    LinearTransform::reduce(&n1, &d2);
+    LinearTransform::reduce(&n2, &d1);
+    LinearTransform::reduce(&n2, &d2);
+
+    cur_trans_.a_zero = new_local_basis;
+    cur_trans_.b_zero = new_common_basis;
+    cur_trans_.a_to_b_numer = n1 * n2;
+    cur_trans_.a_to_b_denom = d1 * d2;
+
+    return OK;
+}
+
+}  // namespace android
diff --git a/services/common_time/common_clock.h b/services/common_time/common_clock.h
new file mode 100644
index 0000000..b786fdc
--- /dev/null
+++ b/services/common_time/common_clock.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __COMMON_CLOCK_H__
+#define __COMMON_CLOCK_H__
+
+#include <stdint.h>
+
+#include <utils/Errors.h>
+#include <utils/LinearTransform.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CommonClock {
+  public:
+    CommonClock();
+
+    bool      init(uint64_t local_freq);
+
+    status_t  localToCommon(int64_t local, int64_t *common_out) const;
+    status_t  commonToLocal(int64_t common, int64_t *local_out) const;
+    int64_t   localDurationToCommonDuration(int64_t localDur) const;
+    uint64_t  getCommonFreq() const { return kCommonFreq; }
+    bool      isValid() const { return cur_trans_valid_; }
+    status_t  setSlew(int64_t change_time, int32_t ppm);
+    void      setBasis(int64_t local, int64_t common);
+    void      resetBasis();
+  private:
+    mutable Mutex lock_;
+
+    int32_t  cur_slew_;
+    uint32_t local_to_common_freq_numer_;
+    uint32_t local_to_common_freq_denom_;
+
+    LinearTransform duration_trans_;
+    LinearTransform cur_trans_;
+    bool cur_trans_valid_;
+
+    static const uint64_t kCommonFreq = 1000000ull;
+};
+
+}  // namespace android
+#endif  // __COMMON_CLOCK_H__
diff --git a/services/common_time/common_clock_service.cpp b/services/common_time/common_clock_service.cpp
new file mode 100644
index 0000000..9ca6f35
--- /dev/null
+++ b/services/common_time/common_clock_service.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <common_time/local_clock.h>
+#include <utils/String8.h>
+
+#include "common_clock_service.h"
+#include "common_clock.h"
+#include "common_time_server.h"
+
+namespace android {
+
+sp<CommonClockService> CommonClockService::instantiate(
+        CommonTimeServer& timeServer) {
+    sp<CommonClockService> tcc = new CommonClockService(timeServer);
+    if (tcc == NULL)
+        return NULL;
+
+    defaultServiceManager()->addService(ICommonClock::kServiceName, tcc);
+    return tcc;
+}
+
+status_t CommonClockService::dump(int fd, const Vector<String16>& args) {
+    Mutex::Autolock lock(mRegistrationLock);
+    return mTimeServer.dumpClockInterface(fd, args, mListeners.size());
+}
+
+status_t CommonClockService::isCommonTimeValid(bool* valid,
+                                               uint32_t* timelineID) {
+    return mTimeServer.isCommonTimeValid(valid, timelineID);
+}
+
+status_t CommonClockService::commonTimeToLocalTime(int64_t  commonTime,
+                                                   int64_t* localTime) {
+    return mTimeServer.getCommonClock().commonToLocal(commonTime, localTime);
+}
+
+status_t CommonClockService::localTimeToCommonTime(int64_t  localTime,
+                                                   int64_t* commonTime) {
+    return mTimeServer.getCommonClock().localToCommon(localTime, commonTime);
+}
+
+status_t CommonClockService::getCommonTime(int64_t* commonTime) {
+    return localTimeToCommonTime(mTimeServer.getLocalClock().getLocalTime(), commonTime);
+}
+
+status_t CommonClockService::getCommonFreq(uint64_t* freq) {
+    *freq = mTimeServer.getCommonClock().getCommonFreq();
+    return OK;
+}
+
+status_t CommonClockService::getLocalTime(int64_t* localTime) {
+    *localTime = mTimeServer.getLocalClock().getLocalTime();
+    return OK;
+}
+
+status_t CommonClockService::getLocalFreq(uint64_t* freq) {
+    *freq = mTimeServer.getLocalClock().getLocalFreq();
+    return OK;
+}
+
+status_t CommonClockService::getEstimatedError(int32_t* estimate) {
+    *estimate = mTimeServer.getEstimatedError();
+    return OK;
+}
+
+status_t CommonClockService::getTimelineID(uint64_t* id) {
+    *id = mTimeServer.getTimelineID();
+    return OK;
+}
+
+status_t CommonClockService::getState(State* state) {
+    *state = mTimeServer.getState();
+    return OK;
+}
+
+status_t CommonClockService::getMasterAddr(struct sockaddr_storage* addr) {
+    return mTimeServer.getMasterAddr(addr);
+}
+
+status_t CommonClockService::registerListener(
+        const sp<ICommonClockListener>& listener) {
+    Mutex::Autolock lock(mRegistrationLock);
+
+    {   // scoping for autolock pattern
+        Mutex::Autolock lock(mCallbackLock);
+        // check whether this is a duplicate
+        for (size_t i = 0; i < mListeners.size(); i++) {
+            if (mListeners[i]->asBinder() == listener->asBinder())
+                return ALREADY_EXISTS;
+        }
+    }
+
+    mListeners.add(listener);
+    mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
+    return listener->asBinder()->linkToDeath(this);
+}
+
+status_t CommonClockService::unregisterListener(
+        const sp<ICommonClockListener>& listener) {
+    Mutex::Autolock lock(mRegistrationLock);
+    status_t ret_val = NAME_NOT_FOUND;
+
+    {   // scoping for autolock pattern
+        Mutex::Autolock lock(mCallbackLock);
+        for (size_t i = 0; i < mListeners.size(); i++) {
+            if (mListeners[i]->asBinder() == listener->asBinder()) {
+                mListeners[i]->asBinder()->unlinkToDeath(this);
+                mListeners.removeAt(i);
+                ret_val = OK;
+                break;
+            }
+        }
+    }
+
+    mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
+    return ret_val;
+}
+
+void CommonClockService::binderDied(const wp<IBinder>& who) {
+    Mutex::Autolock lock(mRegistrationLock);
+
+    {   // scoping for autolock pattern
+        Mutex::Autolock lock(mCallbackLock);
+        for (size_t i = 0; i < mListeners.size(); i++) {
+            if (mListeners[i]->asBinder() == who) {
+                mListeners.removeAt(i);
+                break;
+            }
+        }
+    }
+
+    mTimeServer.reevaluateAutoDisableState(0 != mListeners.size());
+}
+
+void CommonClockService::notifyOnTimelineChanged(uint64_t timelineID) {
+    Mutex::Autolock lock(mCallbackLock);
+
+    for (size_t i = 0; i < mListeners.size(); i++) {
+        mListeners[i]->onTimelineChanged(timelineID);
+    }
+}
+
+}; // namespace android
diff --git a/services/common_time/common_clock_service.h b/services/common_time/common_clock_service.h
new file mode 100644
index 0000000..a65e398
--- /dev/null
+++ b/services/common_time/common_clock_service.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <common_time/ICommonClock.h>
+
+#ifndef ANDROID_COMMON_CLOCK_SERVICE_H
+#define ANDROID_COMMON_CLOCK_SERVICE_H
+
+namespace android {
+
+class CommonTimeServer;
+
+class CommonClockService : public BnCommonClock,
+                           public android::IBinder::DeathRecipient {
+  public:
+    static sp<CommonClockService> instantiate(CommonTimeServer& timeServer);
+
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+    virtual status_t isCommonTimeValid(bool* valid, uint32_t *timelineID);
+    virtual status_t commonTimeToLocalTime(int64_t  common_time,
+                                           int64_t* local_time);
+    virtual status_t localTimeToCommonTime(int64_t  local_time,
+                                           int64_t* common_time);
+    virtual status_t getCommonTime(int64_t* common_time);
+    virtual status_t getCommonFreq(uint64_t* freq);
+    virtual status_t getLocalTime(int64_t* local_time);
+    virtual status_t getLocalFreq(uint64_t* freq);
+    virtual status_t getEstimatedError(int32_t* estimate);
+    virtual status_t getTimelineID(uint64_t* id);
+    virtual status_t getState(ICommonClock::State* state);
+    virtual status_t getMasterAddr(struct sockaddr_storage* addr);
+
+    virtual status_t registerListener(
+            const sp<ICommonClockListener>& listener);
+    virtual status_t unregisterListener(
+            const sp<ICommonClockListener>& listener);
+
+    void notifyOnTimelineChanged(uint64_t timelineID);
+
+  private:
+    CommonClockService(CommonTimeServer& timeServer)
+        : mTimeServer(timeServer) { };
+
+    virtual void binderDied(const wp<IBinder>& who);
+
+    CommonTimeServer& mTimeServer;
+
+    // locks used to synchronize access to the list of registered listeners.
+    // The callback lock is held whenever the list is used to perform callbacks
+    // or while the list is being modified.  The registration lock used to
+    // serialize access across registerListener, unregisterListener, and
+    // binderDied.
+    //
+    // The reason for two locks is that registerListener, unregisterListener,
+    // and binderDied each call into the core service and obtain the core
+    // service thread lock when they call reevaluateAutoDisableState.  The core
+    // service thread obtains the main thread lock whenever its thread is
+    // running, and sometimes needs to call notifyOnTimelineChanged which then
+    // obtains the callback lock.  If callers of registration functions were
+    // holding the callback lock when they called into the core service, we
+    // would have a classic A/B, B/A ordering deadlock.  To avoid this, the
+    // registration functions hold the registration lock for the duration of
+    // their call, but hold the callback lock only while they mutate the list.
+    // This way, the list's size cannot change (because of the registration
+    // lock) during the call into reevaluateAutoDisableState, but the core work
+    // thread can still safely call notifyOnTimelineChanged while holding the
+    // main thread lock.
+    Mutex mCallbackLock;
+    Mutex mRegistrationLock;
+
+    Vector<sp<ICommonClockListener> > mListeners;
+};
+
+};  // namespace android
+
+#endif  // ANDROID_COMMON_CLOCK_SERVICE_H
diff --git a/services/common_time/common_time_config_service.cpp b/services/common_time/common_time_config_service.cpp
new file mode 100644
index 0000000..9585618
--- /dev/null
+++ b/services/common_time/common_time_config_service.cpp
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utils/String8.h>
+
+#include "common_time_config_service.h"
+#include "common_time_server.h"
+
+namespace android {
+
+sp<CommonTimeConfigService> CommonTimeConfigService::instantiate(
+        CommonTimeServer& timeServer) {
+    sp<CommonTimeConfigService> ctcs = new CommonTimeConfigService(timeServer);
+    if (ctcs == NULL)
+        return NULL;
+
+    defaultServiceManager()->addService(ICommonTimeConfig::kServiceName, ctcs);
+    return ctcs;
+}
+
+status_t CommonTimeConfigService::dump(int fd, const Vector<String16>& args) {
+    return mTimeServer.dumpConfigInterface(fd, args);
+}
+
+status_t CommonTimeConfigService::getMasterElectionPriority(uint8_t *priority) {
+    return mTimeServer.getMasterElectionPriority(priority);
+}
+
+status_t CommonTimeConfigService::setMasterElectionPriority(uint8_t priority) {
+    return mTimeServer.setMasterElectionPriority(priority);
+}
+
+status_t CommonTimeConfigService::getMasterElectionEndpoint(
+        struct sockaddr_storage *addr) {
+    return mTimeServer.getMasterElectionEndpoint(addr);
+}
+
+status_t CommonTimeConfigService::setMasterElectionEndpoint(
+        const struct sockaddr_storage *addr) {
+    return mTimeServer.setMasterElectionEndpoint(addr);
+}
+
+status_t CommonTimeConfigService::getMasterElectionGroupId(uint64_t *id) {
+    return mTimeServer.getMasterElectionGroupId(id);
+}
+
+status_t CommonTimeConfigService::setMasterElectionGroupId(uint64_t id) {
+    return mTimeServer.setMasterElectionGroupId(id);
+}
+
+status_t CommonTimeConfigService::getInterfaceBinding(String16& ifaceName) {
+    String8 tmp;
+    status_t ret = mTimeServer.getInterfaceBinding(tmp);
+    ifaceName = String16(tmp);
+    return ret;
+}
+
+status_t CommonTimeConfigService::setInterfaceBinding(const String16& ifaceName) {
+    String8 tmp(ifaceName);
+    return mTimeServer.setInterfaceBinding(tmp);
+}
+
+status_t CommonTimeConfigService::getMasterAnnounceInterval(int *interval) {
+    return mTimeServer.getMasterAnnounceInterval(interval);
+}
+
+status_t CommonTimeConfigService::setMasterAnnounceInterval(int interval) {
+    return mTimeServer.setMasterAnnounceInterval(interval);
+}
+
+status_t CommonTimeConfigService::getClientSyncInterval(int *interval) {
+    return mTimeServer.getClientSyncInterval(interval);
+}
+
+status_t CommonTimeConfigService::setClientSyncInterval(int interval) {
+    return mTimeServer.setClientSyncInterval(interval);
+}
+
+status_t CommonTimeConfigService::getPanicThreshold(int *threshold) {
+    return mTimeServer.getPanicThreshold(threshold);
+}
+
+status_t CommonTimeConfigService::setPanicThreshold(int threshold) {
+    return mTimeServer.setPanicThreshold(threshold);
+}
+
+status_t CommonTimeConfigService::getAutoDisable(bool *autoDisable) {
+    return mTimeServer.getAutoDisable(autoDisable);
+}
+
+status_t CommonTimeConfigService::setAutoDisable(bool autoDisable) {
+    return mTimeServer.setAutoDisable(autoDisable);
+}
+
+status_t CommonTimeConfigService::forceNetworklessMasterMode() {
+    return mTimeServer.forceNetworklessMasterMode();
+}
+
+}; // namespace android
diff --git a/services/common_time/common_time_config_service.h b/services/common_time/common_time_config_service.h
new file mode 100644
index 0000000..8283c24
--- /dev/null
+++ b/services/common_time/common_time_config_service.h
@@ -0,0 +1,59 @@
+/* * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <common_time/ICommonTimeConfig.h>
+
+#ifndef ANDROID_COMMON_TIME_CONFIG_SERVICE_H
+#define ANDROID_COMMON_TIME_CONFIG_SERVICE_H
+
+namespace android {
+
+class String16;
+class CommonTimeServer;
+
+class CommonTimeConfigService : public BnCommonTimeConfig {
+  public:
+    static sp<CommonTimeConfigService> instantiate(CommonTimeServer& timeServer);
+
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+    virtual status_t getMasterElectionPriority(uint8_t *priority);
+    virtual status_t setMasterElectionPriority(uint8_t priority);
+    virtual status_t getMasterElectionEndpoint(struct sockaddr_storage *addr);
+    virtual status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr);
+    virtual status_t getMasterElectionGroupId(uint64_t *id);
+    virtual status_t setMasterElectionGroupId(uint64_t id);
+    virtual status_t getInterfaceBinding(String16& ifaceName);
+    virtual status_t setInterfaceBinding(const String16& ifaceName);
+    virtual status_t getMasterAnnounceInterval(int *interval);
+    virtual status_t setMasterAnnounceInterval(int interval);
+    virtual status_t getClientSyncInterval(int *interval);
+    virtual status_t setClientSyncInterval(int interval);
+    virtual status_t getPanicThreshold(int *threshold);
+    virtual status_t setPanicThreshold(int threshold);
+    virtual status_t getAutoDisable(bool *autoDisable);
+    virtual status_t setAutoDisable(bool autoDisable);
+    virtual status_t forceNetworklessMasterMode();
+
+  private:
+    CommonTimeConfigService(CommonTimeServer& timeServer)
+        : mTimeServer(timeServer) { }
+    CommonTimeServer& mTimeServer;
+
+};
+
+};  // namespace android
+
+#endif  // ANDROID_COMMON_TIME_CONFIG_SERVICE_H
diff --git a/services/common_time/common_time_server.cpp b/services/common_time/common_time_server.cpp
new file mode 100644
index 0000000..ef7fa168
--- /dev/null
+++ b/services/common_time/common_time_server.cpp
@@ -0,0 +1,1380 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <linux/if_ether.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <netinet/ip.h>
+#include <poll.h>
+#include <stdio.h>
+#include <sys/eventfd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <common_time/local_clock.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <utils/Timers.h>
+
+#include "common_clock_service.h"
+#include "common_time_config_service.h"
+#include "common_time_server.h"
+#include "common_time_server_packets.h"
+#include "clock_recovery.h"
+#include "common_clock.h"
+
+#define MAX_INT ((int)0x7FFFFFFF)
+
+namespace android {
+
+const char*    CommonTimeServer::kDefaultMasterElectionAddr = "239.195.128.88";
+const uint16_t CommonTimeServer::kDefaultMasterElectionPort = 8887;
+const uint64_t CommonTimeServer::kDefaultSyncGroupID = 0;
+const uint8_t  CommonTimeServer::kDefaultMasterPriority = 1;
+const uint32_t CommonTimeServer::kDefaultMasterAnnounceIntervalMs = 10000;
+const uint32_t CommonTimeServer::kDefaultSyncRequestIntervalMs = 1000;
+const uint32_t CommonTimeServer::kDefaultPanicThresholdUsec = 50000;
+const bool     CommonTimeServer::kDefaultAutoDisable = true;
+const int      CommonTimeServer::kSetupRetryTimeoutMs = 30000;
+const int64_t  CommonTimeServer::kNoGoodDataPanicThresholdUsec = 600000000ll;
+const uint32_t CommonTimeServer::kRTTDiscardPanicThreshMultiplier = 5;
+
+// timeout value representing an infinite timeout
+const int CommonTimeServer::kInfiniteTimeout = -1;
+
+/*** Initial state constants ***/
+
+// number of WhoIsMaster attempts sent before giving up
+const int CommonTimeServer::kInitial_NumWhoIsMasterRetries = 6;
+
+// timeout used when waiting for a response to a WhoIsMaster request
+const int CommonTimeServer::kInitial_WhoIsMasterTimeoutMs = 500;
+
+/*** Client state constants ***/
+
+// number of sync requests that can fail before a client assumes its master
+// is dead
+const int CommonTimeServer::kClient_NumSyncRequestRetries = 5;
+
+/*** Master state constants ***/
+
+/*** Ronin state constants ***/
+
+// number of WhoIsMaster attempts sent before declaring ourselves master
+const int CommonTimeServer::kRonin_NumWhoIsMasterRetries = 4;
+
+// timeout used when waiting for a response to a WhoIsMaster request
+const int CommonTimeServer::kRonin_WhoIsMasterTimeoutMs = 500;
+
+/*** WaitForElection state constants ***/
+
+// how long do we wait for an announcement from a master before
+// trying another election?
+const int CommonTimeServer::kWaitForElection_TimeoutMs = 5000;
+
+CommonTimeServer::CommonTimeServer()
+    : Thread(false)
+    , mState(ICommonClock::STATE_INITIAL)
+    , mClockRecovery(&mLocalClock, &mCommonClock)
+    , mSocket(-1)
+    , mLastPacketRxLocalTime(0)
+    , mTimelineID(ICommonClock::kInvalidTimelineID)
+    , mClockSynced(false)
+    , mCommonClockHasClients(false)
+    , mInitial_WhoIsMasterRequestTimeouts(0)
+    , mClient_MasterDeviceID(0)
+    , mClient_MasterDevicePriority(0)
+    , mRonin_WhoIsMasterRequestTimeouts(0) {
+    // zero out sync stats
+    resetSyncStats();
+
+    // Setup the master election endpoint to use the default.
+    struct sockaddr_in* meep =
+        reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP);
+    memset(&mMasterElectionEP, 0, sizeof(mMasterElectionEP));
+    inet_aton(kDefaultMasterElectionAddr, &meep->sin_addr);
+    meep->sin_family = AF_INET;
+    meep->sin_port   = htons(kDefaultMasterElectionPort);
+
+    // Zero out the master endpoint.
+    memset(&mMasterEP, 0, sizeof(mMasterEP));
+    mMasterEPValid    = false;
+    mBindIfaceValid   = false;
+    setForceLowPriority(false);
+
+    // Set all remaining configuration parameters to their defaults.
+    mDeviceID                 = 0;
+    mSyncGroupID              = kDefaultSyncGroupID;
+    mMasterPriority           = kDefaultMasterPriority;
+    mMasterAnnounceIntervalMs = kDefaultMasterAnnounceIntervalMs;
+    mSyncRequestIntervalMs    = kDefaultSyncRequestIntervalMs;
+    mPanicThresholdUsec       = kDefaultPanicThresholdUsec;
+    mAutoDisable              = kDefaultAutoDisable;
+
+    // Create the eventfd we will use to signal our thread to wake up when
+    // needed.
+    mWakeupThreadFD = eventfd(0, EFD_NONBLOCK);
+
+    // seed the random number generator (used to generated timeline IDs)
+    srand48(static_cast<unsigned int>(systemTime()));
+}
+
+CommonTimeServer::~CommonTimeServer() {
+    shutdownThread();
+
+    // No need to grab the lock here.  We are in the destructor; if the the user
+    // has a thread in any of the APIs while the destructor is being called,
+    // there is a threading problem a the application level we cannot reasonably
+    // do anything about.
+    cleanupSocket_l();
+
+    if (mWakeupThreadFD >= 0) {
+        close(mWakeupThreadFD);
+        mWakeupThreadFD = -1;
+    }
+}
+
+bool CommonTimeServer::startServices() {
+    // start the ICommonClock service
+    mICommonClock = CommonClockService::instantiate(*this);
+    if (mICommonClock == NULL)
+        return false;
+
+    // start the ICommonTimeConfig service
+    mICommonTimeConfig = CommonTimeConfigService::instantiate(*this);
+    if (mICommonTimeConfig == NULL)
+        return false;
+
+    return true;
+}
+
+bool CommonTimeServer::threadLoop() {
+    // Register our service interfaces.
+    if (!startServices())
+        return false;
+
+    // Hold the lock while we are in the main thread loop.  It will release the
+    // lock when it blocks, and hold the lock at all other times.
+    mLock.lock();
+    runStateMachine_l();
+    mLock.unlock();
+
+    IPCThreadState::self()->stopProcess();
+    return false;
+}
+
+bool CommonTimeServer::runStateMachine_l() {
+    if (!mLocalClock.initCheck())
+        return false;
+
+    if (!mCommonClock.init(mLocalClock.getLocalFreq()))
+        return false;
+
+    // Enter the initial state.
+    becomeInitial("startup");
+
+    // run the state machine
+    while (!exitPending()) {
+        struct pollfd pfds[2];
+        int rc;
+        int eventCnt = 0;
+        int64_t wakeupTime;
+
+        // We are always interested in our wakeup FD.
+        pfds[eventCnt].fd      = mWakeupThreadFD;
+        pfds[eventCnt].events  = POLLIN;
+        pfds[eventCnt].revents = 0;
+        eventCnt++;
+
+        // If we have a valid socket, then we are interested in what it has to
+        // say as well.
+        if (mSocket >= 0) {
+            pfds[eventCnt].fd      = mSocket;
+            pfds[eventCnt].events  = POLLIN;
+            pfds[eventCnt].revents = 0;
+            eventCnt++;
+        }
+
+        // Note, we were holding mLock when this function was called.  We
+        // release it only while we are blocking and hold it at all other times.
+        mLock.unlock();
+        rc          = poll(pfds, eventCnt, mCurTimeout.msecTillTimeout());
+        wakeupTime  = mLocalClock.getLocalTime();
+        mLock.lock();
+
+        // Is it time to shutdown?  If so, don't hesitate... just do it.
+        if (exitPending())
+            break;
+
+        // Did the poll fail?  This should never happen and is fatal if it does.
+        if (rc < 0) {
+            ALOGE("%s:%d poll failed", __PRETTY_FUNCTION__, __LINE__);
+            return false;
+        }
+
+        if (rc == 0)
+            mCurTimeout.setTimeout(kInfiniteTimeout);
+
+        // Were we woken up on purpose?  If so, clear the eventfd with a read.
+        if (pfds[0].revents)
+            clearPendingWakeupEvents_l();
+
+        // Is out bind address dirty?  If so, clean up our socket (if any).
+        // Alternatively, do we have an active socket but should be auto
+        // disabled?  If so, release the socket and enter the proper sync state.
+        bool droppedSocket = false;
+        if (mBindIfaceDirty || ((mSocket >= 0) && shouldAutoDisable())) {
+            cleanupSocket_l();
+            mBindIfaceDirty = false;
+            droppedSocket = true;
+        }
+
+        // Do we not have a socket but should have one?  If so, try to set one
+        // up.
+        if ((mSocket < 0) && mBindIfaceValid && !shouldAutoDisable()) {
+            if (setupSocket_l()) {
+                // Success!  We are now joining a new network (either coming
+                // from no network, or coming from a potentially different
+                // network).  Force our priority to be lower so that we defer to
+                // any other masters which may already be on the network we are
+                // joining.  Later, when we enter either the client or the
+                // master state, we will clear this flag and go back to our
+                // normal election priority.
+                setForceLowPriority(true);
+                switch (mState) {
+                    // If we were in initial (whether we had a immediately
+                    // before this network or not) we want to simply reset the
+                    // system and start again.  Forcing a transition from
+                    // INITIAL to INITIAL should do the job.
+                    case CommonClockService::STATE_INITIAL:
+                        becomeInitial("bound interface");
+                        break;
+
+                    // If we were in the master state, then either we were the
+                    // master in a no-network situation, or we were the master
+                    // of a different network and have moved to a new interface.
+                    // In either case, immediately send out a master
+                    // announcement at low priority.
+                    case CommonClockService::STATE_MASTER:
+                        sendMasterAnnouncement();
+                        break;
+
+                    // If we were in any other state (CLIENT, RONIN, or
+                    // WAIT_FOR_ELECTION) then we must be moving from one
+                    // network to another.  We have lost our old master;
+                    // transition to RONIN in an attempt to find a new master.
+                    // If there are none out there, we will just assume
+                    // responsibility for the timeline we used to be a client
+                    // of.
+                    default:
+                        becomeRonin("bound interface");
+                        break;
+                }
+            } else {
+                // That's odd... we failed to set up our socket.  This could be
+                // due to some transient network change which will work itself
+                // out shortly; schedule a retry attempt in the near future.
+                mCurTimeout.setTimeout(kSetupRetryTimeoutMs);
+            }
+
+            // One way or the other, we don't have any data to process at this
+            // point (since we just tried to bulid a new socket).  Loop back
+            // around and wait for the next thing to do.
+            continue;
+        } else if (droppedSocket) {
+            // We just lost our socket, and for whatever reason (either no
+            // config, or auto disable engaged) we are not supposed to rebuild
+            // one at this time.  We are not going to rebuild our socket until
+            // something about our config/auto-disabled status changes, so we
+            // are basically in network-less mode.  If we are already in either
+            // INITIAL or MASTER, just stay there until something changes.  If
+            // we are in any other state (CLIENT, RONIN or WAIT_FOR_ELECTION),
+            // then transition to either INITIAL or MASTER depending on whether
+            // or not our timeline is valid.
+            ALOGI("Entering networkless mode interface is %s, "
+                 "shouldAutoDisable = %s",
+                 mBindIfaceValid ? "valid" : "invalid",
+                 shouldAutoDisable() ? "true" : "false");
+            if ((mState != ICommonClock::STATE_INITIAL) &&
+                (mState != ICommonClock::STATE_MASTER)) {
+                if (mTimelineID == ICommonClock::kInvalidTimelineID)
+                    becomeInitial("network-less mode");
+                else
+                    becomeMaster("network-less mode");
+            }
+
+            continue;
+        }
+
+        // Did we wakeup with no signalled events across all of our FDs?  If so,
+        // we must have hit our timeout.
+        if (rc == 0) {
+            if (!handleTimeout())
+                ALOGE("handleTimeout failed");
+            continue;
+        }
+
+        // Does our socket have data for us (assuming we still have one, we
+        // may have RXed a packet at the same time as a config change telling us
+        // to shut our socket down)?  If so, process its data.
+        if ((mSocket >= 0) && (eventCnt > 1) && (pfds[1].revents)) {
+            mLastPacketRxLocalTime = wakeupTime;
+            if (!handlePacket())
+                ALOGE("handlePacket failed");
+        }
+    }
+
+    cleanupSocket_l();
+    return true;
+}
+
+void CommonTimeServer::clearPendingWakeupEvents_l() {
+    int64_t tmp;
+    read(mWakeupThreadFD, &tmp, sizeof(tmp));
+}
+
+void CommonTimeServer::wakeupThread_l() {
+    int64_t tmp = 1;
+    write(mWakeupThreadFD, &tmp, sizeof(tmp));
+}
+
+void CommonTimeServer::cleanupSocket_l() {
+    if (mSocket >= 0) {
+        close(mSocket);
+        mSocket = -1;
+    }
+}
+
+void CommonTimeServer::shutdownThread() {
+    // Flag the work thread for shutdown.
+    this->requestExit();
+
+    // Signal the thread in case its sleeping.
+    mLock.lock();
+    wakeupThread_l();
+    mLock.unlock();
+
+    // Wait for the thread to exit.
+    this->join();
+}
+
+bool CommonTimeServer::setupSocket_l() {
+    int rc;
+    bool ret_val = false;
+    struct sockaddr_in* ipv4_addr = NULL;
+    char masterElectionEPStr[64];
+    const int one = 1;
+
+    // This should never be needed, but if we happened to have an old socket
+    // lying around, be sure to not leak it before proceeding.
+    cleanupSocket_l();
+
+    // If we don't have a valid endpoint to bind to, then how did we get here in
+    // the first place?  Regardless, we know that we are going to fail to bind,
+    // so don't even try.
+    if (!mBindIfaceValid)
+        return false;
+
+    sockaddrToString(mMasterElectionEP, true, masterElectionEPStr,
+                     sizeof(masterElectionEPStr));
+    ALOGI("Building socket :: bind = %s master election = %s",
+         mBindIface.string(), masterElectionEPStr);
+
+    // TODO: add proper support for IPv6.  Right now, we block IPv6 addresses at
+    // the configuration interface level.
+    if (AF_INET != mMasterElectionEP.ss_family) {
+        ALOGW("TODO: add proper IPv6 support");
+        goto bailout;
+    }
+
+    // open a UDP socket for the timeline serivce
+    mSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    if (mSocket < 0) {
+        ALOGE("Failed to create socket (errno = %d)", errno);
+        goto bailout;
+    }
+
+    // Bind to the selected interface using Linux's spiffy SO_BINDTODEVICE.
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", mBindIface.string());
+    ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = 0;
+    rc = setsockopt(mSocket, SOL_SOCKET, SO_BINDTODEVICE,
+                    (void *)&ifr, sizeof(ifr));
+    if (rc) {
+        ALOGE("Failed to bind socket at to interface %s (errno = %d)",
+              ifr.ifr_name, errno);
+        goto bailout;
+    }
+
+    // Bind our socket to INADDR_ANY and the master election port.  The
+    // interface binding we made using SO_BINDTODEVICE should limit us to
+    // traffic only on the interface we are interested in.  We need to bind to
+    // INADDR_ANY and the specific master election port in order to be able to
+    // receive both unicast traffic and master election multicast traffic with
+    // just a single socket.
+    struct sockaddr_in bindAddr;
+    ipv4_addr = reinterpret_cast<struct sockaddr_in*>(&mMasterElectionEP);
+    memcpy(&bindAddr, ipv4_addr, sizeof(bindAddr));
+    bindAddr.sin_addr.s_addr = INADDR_ANY;
+    rc = bind(mSocket,
+              reinterpret_cast<const sockaddr *>(&bindAddr),
+              sizeof(bindAddr));
+    if (rc) {
+        ALOGE("Failed to bind socket to port %hu (errno = %d)",
+              ntohs(bindAddr.sin_port), errno);
+        goto bailout;
+    }
+
+    if (0xE0000000 == (ntohl(ipv4_addr->sin_addr.s_addr) & 0xF0000000)) {
+        // If our master election endpoint is a multicast address, be sure to join
+        // the multicast group.
+        struct ip_mreq mreq;
+        mreq.imr_multiaddr = ipv4_addr->sin_addr;
+        mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+        rc = setsockopt(mSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+                        &mreq, sizeof(mreq));
+        if (rc == -1) {
+            ALOGE("Failed to join multicast group at %s.  (errno = %d)",
+                 masterElectionEPStr, errno);
+            goto bailout;
+        }
+
+        // disable loopback of multicast packets
+        const int zero = 0;
+        rc = setsockopt(mSocket, IPPROTO_IP, IP_MULTICAST_LOOP,
+                        &zero, sizeof(zero));
+        if (rc == -1) {
+            ALOGE("Failed to disable multicast loopback (errno = %d)", errno);
+            goto bailout;
+        }
+    } else
+    if (ntohl(ipv4_addr->sin_addr.s_addr) != 0xFFFFFFFF) {
+        // If the master election address is neither broadcast, nor multicast,
+        // then we are misconfigured.  The config API layer should prevent this
+        // from ever happening.
+        goto bailout;
+    }
+
+    // Set the TTL of sent packets to 1.  (Time protocol sync should never leave
+    // the local subnet)
+    rc = setsockopt(mSocket, IPPROTO_IP, IP_TTL, &one, sizeof(one));
+    if (rc == -1) {
+        ALOGE("Failed to set TTL to %d (errno = %d)", one, errno);
+        goto bailout;
+    }
+
+    // get the device's unique ID
+    if (!assignDeviceID())
+        goto bailout;
+
+    ret_val = true;
+
+bailout:
+    if (!ret_val)
+        cleanupSocket_l();
+    return ret_val;
+}
+
+// generate a unique device ID that can be used for arbitration
+bool CommonTimeServer::assignDeviceID() {
+    if (!mBindIfaceValid)
+        return false;
+
+    struct ifreq ifr;
+    memset(&ifr, 0, sizeof(ifr));
+    ifr.ifr_addr.sa_family = AF_INET;
+    strlcpy(ifr.ifr_name, mBindIface.string(), IFNAMSIZ);
+
+    int rc = ioctl(mSocket, SIOCGIFHWADDR, &ifr);
+    if (rc) {
+        ALOGE("%s:%d ioctl failed", __PRETTY_FUNCTION__, __LINE__);
+        return false;
+    }
+
+    if (ifr.ifr_addr.sa_family != ARPHRD_ETHER) {
+        ALOGE("%s:%d got non-Ethernet address", __PRETTY_FUNCTION__, __LINE__);
+        return false;
+    }
+
+    mDeviceID = 0;
+    for (int i = 0; i < ETH_ALEN; i++) {
+        mDeviceID = (mDeviceID << 8) | ifr.ifr_hwaddr.sa_data[i];
+    }
+
+    return true;
+}
+
+// generate a new timeline ID
+void CommonTimeServer::assignTimelineID() {
+    do {
+        mTimelineID = (static_cast<uint64_t>(lrand48()) << 32)
+                    |  static_cast<uint64_t>(lrand48());
+    } while (mTimelineID == ICommonClock::kInvalidTimelineID);
+}
+
+// Select a preference between the device IDs of two potential masters.
+// Returns true if the first ID wins, or false if the second ID wins.
+bool CommonTimeServer::arbitrateMaster(
+        uint64_t deviceID1, uint8_t devicePrio1,
+        uint64_t deviceID2, uint8_t devicePrio2) {
+    return ((devicePrio1 >  devicePrio2) ||
+           ((devicePrio1 == devicePrio2) && (deviceID1 > deviceID2)));
+}
+
+bool CommonTimeServer::handlePacket() {
+    uint8_t buf[256];
+    struct sockaddr_storage srcAddr;
+    socklen_t srcAddrLen = sizeof(srcAddr);
+
+    ssize_t recvBytes = recvfrom(
+            mSocket, buf, sizeof(buf), 0,
+            reinterpret_cast<const sockaddr *>(&srcAddr), &srcAddrLen);
+
+    if (recvBytes < 0) {
+        ALOGE("%s:%d recvfrom failed", __PRETTY_FUNCTION__, __LINE__);
+        return false;
+    }
+
+    UniversalTimeServicePacket pkt;
+    recvBytes = pkt.deserializePacket(buf, recvBytes, mSyncGroupID);
+    if (recvBytes < 0)
+        return false;
+
+    bool result;
+    switch (pkt.packetType) {
+        case TIME_PACKET_WHO_IS_MASTER_REQUEST:
+            result = handleWhoIsMasterRequest(&pkt.p.who_is_master_request,
+                                              srcAddr);
+            break;
+
+        case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
+            result = handleWhoIsMasterResponse(&pkt.p.who_is_master_response,
+                                               srcAddr);
+            break;
+
+        case TIME_PACKET_SYNC_REQUEST:
+            result = handleSyncRequest(&pkt.p.sync_request, srcAddr);
+            break;
+
+        case TIME_PACKET_SYNC_RESPONSE:
+            result = handleSyncResponse(&pkt.p.sync_response, srcAddr);
+            break;
+
+        case TIME_PACKET_MASTER_ANNOUNCEMENT:
+            result = handleMasterAnnouncement(&pkt.p.master_announcement,
+                                              srcAddr);
+            break;
+
+        default: {
+            ALOGD("%s:%d unknown packet type(%d)",
+                    __PRETTY_FUNCTION__, __LINE__, pkt.packetType);
+            result = false;
+        } break;
+    }
+
+    return result;
+}
+
+bool CommonTimeServer::handleTimeout() {
+    // If we have no socket, then this must be a timeout to retry socket setup.
+    if (mSocket < 0)
+        return true;
+
+    switch (mState) {
+        case ICommonClock::STATE_INITIAL:
+            return handleTimeoutInitial();
+        case ICommonClock::STATE_CLIENT:
+            return handleTimeoutClient();
+        case ICommonClock::STATE_MASTER:
+            return handleTimeoutMaster();
+        case ICommonClock::STATE_RONIN:
+            return handleTimeoutRonin();
+        case ICommonClock::STATE_WAIT_FOR_ELECTION:
+            return handleTimeoutWaitForElection();
+    }
+
+    return false;
+}
+
+bool CommonTimeServer::handleTimeoutInitial() {
+    if (++mInitial_WhoIsMasterRequestTimeouts ==
+            kInitial_NumWhoIsMasterRetries) {
+        // none of our attempts to discover a master succeeded, so make
+        // this device the master
+        return becomeMaster("initial timeout");
+    } else {
+        // retry the WhoIsMaster request
+        return sendWhoIsMasterRequest();
+    }
+}
+
+bool CommonTimeServer::handleTimeoutClient() {
+    if (shouldPanicNotGettingGoodData())
+        return becomeInitial("timeout panic, no good data");
+
+    if (mClient_SyncRequestPending) {
+        mClient_SyncRequestPending = false;
+
+        if (++mClient_SyncRequestTimeouts < kClient_NumSyncRequestRetries) {
+            // a sync request has timed out, so retry
+            return sendSyncRequest();
+        } else {
+            // The master has failed to respond to a sync request for too many
+            // times in a row.  Assume the master is dead and start electing
+            // a new master.
+            return becomeRonin("master not responding");
+        }
+    } else {
+        // initiate the next sync request
+        return sendSyncRequest();
+    }
+}
+
+bool CommonTimeServer::handleTimeoutMaster() {
+    // send another announcement from the master
+    return sendMasterAnnouncement();
+}
+
+bool CommonTimeServer::handleTimeoutRonin() {
+    if (++mRonin_WhoIsMasterRequestTimeouts == kRonin_NumWhoIsMasterRetries) {
+        // no other master is out there, so we won the election
+        return becomeMaster("no better masters detected");
+    } else {
+        return sendWhoIsMasterRequest();
+    }
+}
+
+bool CommonTimeServer::handleTimeoutWaitForElection() {
+    return becomeRonin("timeout waiting for election conclusion");
+}
+
+bool CommonTimeServer::handleWhoIsMasterRequest(
+        const WhoIsMasterRequestPacket* request,
+        const sockaddr_storage& srcAddr) {
+    if (mState == ICommonClock::STATE_MASTER) {
+        // is this request related to this master's timeline?
+        if (request->timelineID != ICommonClock::kInvalidTimelineID &&
+            request->timelineID != mTimelineID)
+            return true;
+
+        WhoIsMasterResponsePacket pkt;
+        pkt.initHeader(mTimelineID, mSyncGroupID);
+        pkt.deviceID = mDeviceID;
+        pkt.devicePriority = effectivePriority();
+
+        uint8_t buf[256];
+        ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+        if (bufSz < 0)
+            return false;
+
+        ssize_t sendBytes = sendto(
+                mSocket, buf, bufSz, 0,
+                reinterpret_cast<const sockaddr *>(&srcAddr),
+                sizeof(srcAddr));
+        if (sendBytes == -1) {
+            ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__);
+            return false;
+        }
+    } else if (mState == ICommonClock::STATE_RONIN) {
+        // if we hear a WhoIsMaster request from another device following
+        // the same timeline and that device wins arbitration, then we will stop
+        // trying to elect ourselves master and will instead wait for an
+        // announcement from the election winner
+        if (request->timelineID != mTimelineID)
+            return true;
+
+        if (arbitrateMaster(request->senderDeviceID,
+                            request->senderDevicePriority,
+                            mDeviceID,
+                            effectivePriority()))
+            return becomeWaitForElection("would lose election");
+
+        return true;
+    } else if (mState == ICommonClock::STATE_INITIAL) {
+        // If a group of devices booted simultaneously (e.g. after a power
+        // outage) and all of them are in the initial state and there is no
+        // master, then each device may time out and declare itself master at
+        // the same time.  To avoid this, listen for
+        // WhoIsMaster(InvalidTimeline) requests from peers.  If we would lose
+        // arbitration against that peer, reset our timeout count so that the
+        // peer has a chance to become master before we time out.
+        if (request->timelineID == ICommonClock::kInvalidTimelineID &&
+                arbitrateMaster(request->senderDeviceID,
+                                request->senderDevicePriority,
+                                mDeviceID,
+                                effectivePriority())) {
+            mInitial_WhoIsMasterRequestTimeouts = 0;
+        }
+    }
+
+    return true;
+}
+
+bool CommonTimeServer::handleWhoIsMasterResponse(
+        const WhoIsMasterResponsePacket* response,
+        const sockaddr_storage& srcAddr) {
+    if (mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN) {
+        return becomeClient(srcAddr,
+                            response->deviceID,
+                            response->devicePriority,
+                            response->timelineID,
+                            "heard whois response");
+    } else if (mState == ICommonClock::STATE_CLIENT) {
+        // if we get multiple responses because there are multiple devices
+        // who believe that they are master, then follow the master that
+        // wins arbitration
+        if (arbitrateMaster(response->deviceID,
+                            response->devicePriority,
+                            mClient_MasterDeviceID,
+                            mClient_MasterDevicePriority)) {
+            return becomeClient(srcAddr,
+                                response->deviceID,
+                                response->devicePriority,
+                                response->timelineID,
+                                "heard whois response");
+        }
+    }
+
+    return true;
+}
+
+bool CommonTimeServer::handleSyncRequest(const SyncRequestPacket* request,
+                                         const sockaddr_storage& srcAddr) {
+    SyncResponsePacket pkt;
+    pkt.initHeader(mTimelineID, mSyncGroupID);
+
+    if ((mState == ICommonClock::STATE_MASTER) &&
+        (mTimelineID == request->timelineID)) {
+        int64_t rxLocalTime = mLastPacketRxLocalTime;
+        int64_t rxCommonTime;
+
+        // If we are master on an actual network and have actual clients, then
+        // we are no longer low priority.
+        setForceLowPriority(false);
+
+        if (OK != mCommonClock.localToCommon(rxLocalTime, &rxCommonTime)) {
+            return false;
+        }
+
+        int64_t txLocalTime = mLocalClock.getLocalTime();;
+        int64_t txCommonTime;
+        if (OK != mCommonClock.localToCommon(txLocalTime, &txCommonTime)) {
+            return false;
+        }
+
+        pkt.nak = 0;
+        pkt.clientTxLocalTime  = request->clientTxLocalTime;
+        pkt.masterRxCommonTime = rxCommonTime;
+        pkt.masterTxCommonTime = txCommonTime;
+    } else {
+        pkt.nak = 1;
+        pkt.clientTxLocalTime  = 0;
+        pkt.masterRxCommonTime = 0;
+        pkt.masterTxCommonTime = 0;
+    }
+
+    uint8_t buf[256];
+    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+    if (bufSz < 0)
+        return false;
+
+    ssize_t sendBytes = sendto(
+            mSocket, &buf, bufSz, 0,
+            reinterpret_cast<const sockaddr *>(&srcAddr),
+            sizeof(srcAddr));
+    if (sendBytes == -1) {
+        ALOGE("%s:%d sendto failed", __PRETTY_FUNCTION__, __LINE__);
+        return false;
+    }
+
+    return true;
+}
+
+bool CommonTimeServer::handleSyncResponse(
+        const SyncResponsePacket* response,
+        const sockaddr_storage& srcAddr) {
+    if (mState != ICommonClock::STATE_CLIENT)
+        return true;
+
+    assert(mMasterEPValid);
+    if (!sockaddrMatch(srcAddr, mMasterEP, true)) {
+        char srcEP[64], expectedEP[64];
+        sockaddrToString(srcAddr, true, srcEP, sizeof(srcEP));
+        sockaddrToString(mMasterEP, true, expectedEP, sizeof(expectedEP));
+        ALOGI("Dropping sync response from unexpected address."
+             " Expected %s Got %s", expectedEP, srcEP);
+        return true;
+    }
+
+    if (response->nak) {
+        // if our master is no longer accepting requests, then we need to find
+        // a new master
+        return becomeRonin("master NAK'ed");
+    }
+
+    mClient_SyncRequestPending = 0;
+    mClient_SyncRequestTimeouts = 0;
+    mClient_PacketRTTLog.logRX(response->clientTxLocalTime,
+                               mLastPacketRxLocalTime);
+
+    bool result;
+    if (!(mClient_SyncRespsRXedFromCurMaster++)) {
+        // the first request/response exchange between a client and a master
+        // may take unusually long due to ARP, so discard it.
+        result = true;
+    } else {
+        int64_t clientTxLocalTime  = response->clientTxLocalTime;
+        int64_t clientRxLocalTime  = mLastPacketRxLocalTime;
+        int64_t masterTxCommonTime = response->masterTxCommonTime;
+        int64_t masterRxCommonTime = response->masterRxCommonTime;
+
+        int64_t rtt       = (clientRxLocalTime - clientTxLocalTime);
+        int64_t avgLocal  = (clientTxLocalTime + clientRxLocalTime) >> 1;
+        int64_t avgCommon = (masterTxCommonTime + masterRxCommonTime) >> 1;
+
+        // if the RTT of the packet is significantly larger than the panic
+        // threshold, we should simply discard it.  Its better to do nothing
+        // than to take cues from a packet like that.
+        int rttCommon = mCommonClock.localDurationToCommonDuration(rtt);
+        if (rttCommon > (static_cast<int64_t>(mPanicThresholdUsec) * 
+                         kRTTDiscardPanicThreshMultiplier)) {
+            ALOGV("Dropping sync response with RTT of %lld uSec", rttCommon);
+            mClient_ExpiredSyncRespsRXedFromCurMaster++;
+            if (shouldPanicNotGettingGoodData())
+                return becomeInitial("RX panic, no good data");
+        } else {
+            result = mClockRecovery.pushDisciplineEvent(avgLocal, avgCommon, rttCommon);
+            mClient_LastGoodSyncRX = clientRxLocalTime;
+
+            if (result) {
+                // indicate to listeners that we've synced to the common timeline
+                notifyClockSync();
+            } else {
+                ALOGE("Panic!  Observed clock sync error is too high to tolerate,"
+                        " resetting state machine and starting over.");
+                notifyClockSyncLoss();
+                return becomeInitial("panic");
+            }
+        }
+    }
+
+    mCurTimeout.setTimeout(mSyncRequestIntervalMs);
+    return result;
+}
+
+bool CommonTimeServer::handleMasterAnnouncement(
+        const MasterAnnouncementPacket* packet,
+        const sockaddr_storage& srcAddr) {
+    uint64_t newDeviceID   = packet->deviceID;
+    uint8_t  newDevicePrio = packet->devicePriority;
+    uint64_t newTimelineID = packet->timelineID;
+
+    if (mState == ICommonClock::STATE_INITIAL ||
+        mState == ICommonClock::STATE_RONIN ||
+        mState == ICommonClock::STATE_WAIT_FOR_ELECTION) {
+        // if we aren't currently following a master, then start following
+        // this new master
+        return becomeClient(srcAddr,
+                            newDeviceID,
+                            newDevicePrio,
+                            newTimelineID,
+                            "heard master announcement");
+    } else if (mState == ICommonClock::STATE_CLIENT) {
+        // if the new master wins arbitration against our current master,
+        // then become a client of the new master
+        if (arbitrateMaster(newDeviceID,
+                            newDevicePrio,
+                            mClient_MasterDeviceID,
+                            mClient_MasterDevicePriority))
+            return becomeClient(srcAddr,
+                                newDeviceID,
+                                newDevicePrio,
+                                newTimelineID,
+                                "heard master announcement");
+    } else if (mState == ICommonClock::STATE_MASTER) {
+        // two masters are competing - if the new one wins arbitration, then
+        // cease acting as master
+        if (arbitrateMaster(newDeviceID, newDevicePrio,
+                            mDeviceID, effectivePriority()))
+            return becomeClient(srcAddr, newDeviceID,
+                                newDevicePrio, newTimelineID,
+                                "heard master announcement");
+    }
+
+    return true;
+}
+
+bool CommonTimeServer::sendWhoIsMasterRequest() {
+    assert(mState == ICommonClock::STATE_INITIAL || mState == ICommonClock::STATE_RONIN);
+
+    // If we have no socket, then we must be in the unconfigured initial state.
+    // Don't report any errors, just don't try to send the initial who-is-master
+    // query.  Eventually, our network will either become configured, or we will
+    // be forced into network-less master mode by higher level code.
+    if (mSocket < 0) {
+        assert(mState == ICommonClock::STATE_INITIAL);
+        return true;
+    }
+
+    bool ret = false;
+    WhoIsMasterRequestPacket pkt;
+    pkt.initHeader(mSyncGroupID);
+    pkt.senderDeviceID = mDeviceID;
+    pkt.senderDevicePriority = effectivePriority();
+
+    uint8_t buf[256];
+    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+    if (bufSz >= 0) {
+        ssize_t sendBytes = sendto(
+                mSocket, buf, bufSz, 0,
+                reinterpret_cast<const sockaddr *>(&mMasterElectionEP),
+                sizeof(mMasterElectionEP));
+        if (sendBytes < 0)
+            ALOGE("WhoIsMaster sendto failed (errno %d)", errno);
+        ret = true;
+    }
+
+    if (mState == ICommonClock::STATE_INITIAL) {
+        mCurTimeout.setTimeout(kInitial_WhoIsMasterTimeoutMs);
+    } else {
+        mCurTimeout.setTimeout(kRonin_WhoIsMasterTimeoutMs);
+    }
+
+    return ret;
+}
+
+bool CommonTimeServer::sendSyncRequest() {
+    // If we are sending sync requests, then we must be in the client state and
+    // we must have a socket (when we have no network, we are only supposed to
+    // be in INITIAL or MASTER)
+    assert(mState == ICommonClock::STATE_CLIENT);
+    assert(mSocket >= 0);
+
+    bool ret = false;
+    SyncRequestPacket pkt;
+    pkt.initHeader(mTimelineID, mSyncGroupID);
+    pkt.clientTxLocalTime = mLocalClock.getLocalTime();
+
+    if (!mClient_FirstSyncTX)
+        mClient_FirstSyncTX = pkt.clientTxLocalTime;
+
+    mClient_PacketRTTLog.logTX(pkt.clientTxLocalTime);
+
+    uint8_t buf[256];
+    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+    if (bufSz >= 0) {
+        ssize_t sendBytes = sendto(
+                mSocket, buf, bufSz, 0,
+                reinterpret_cast<const sockaddr *>(&mMasterEP),
+                sizeof(mMasterEP));
+        if (sendBytes < 0)
+            ALOGE("SyncRequest sendto failed (errno %d)", errno);
+        ret = true;
+    }
+
+    mClient_SyncsSentToCurMaster++;
+    mCurTimeout.setTimeout(mSyncRequestIntervalMs);
+    mClient_SyncRequestPending = true;
+
+    return ret;
+}
+
+bool CommonTimeServer::sendMasterAnnouncement() {
+    bool ret = false;
+    assert(mState == ICommonClock::STATE_MASTER);
+
+    // If we are being asked to send a master announcement, but we have no
+    // socket, we must be in network-less master mode.  Don't bother to send the
+    // announcement, and don't bother to schedule a timeout.  When the network
+    // comes up, the work thread will get poked and start the process of
+    // figuring out who the current master should be.
+    if (mSocket < 0) {
+        mCurTimeout.setTimeout(kInfiniteTimeout);
+        return true;
+    }
+
+    MasterAnnouncementPacket pkt;
+    pkt.initHeader(mTimelineID, mSyncGroupID);
+    pkt.deviceID = mDeviceID;
+    pkt.devicePriority = effectivePriority();
+
+    uint8_t buf[256];
+    ssize_t bufSz = pkt.serializePacket(buf, sizeof(buf));
+    if (bufSz >= 0) {
+        ssize_t sendBytes = sendto(
+                mSocket, buf, bufSz, 0,
+                reinterpret_cast<const sockaddr *>(&mMasterElectionEP),
+                sizeof(mMasterElectionEP));
+        if (sendBytes < 0)
+            ALOGE("MasterAnnouncement sendto failed (errno %d)", errno);
+        ret = true;
+    }
+
+    mCurTimeout.setTimeout(mMasterAnnounceIntervalMs);
+    return ret;
+}
+
+bool CommonTimeServer::becomeClient(const sockaddr_storage& masterEP,
+                                    uint64_t masterDeviceID,
+                                    uint8_t  masterDevicePriority,
+                                    uint64_t timelineID,
+                                    const char* cause) {
+    char newEPStr[64], oldEPStr[64];
+    sockaddrToString(masterEP, true, newEPStr, sizeof(newEPStr));
+    sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr));
+
+    ALOGI("%s --> CLIENT (%s) :%s"
+         " OldMaster: %02x-%014llx::%016llx::%s"
+         " NewMaster: %02x-%014llx::%016llx::%s",
+         stateToString(mState), cause,
+         (mTimelineID != timelineID) ? " (new timeline)" : "",
+         mClient_MasterDevicePriority, mClient_MasterDeviceID,
+         mTimelineID, oldEPStr,
+         masterDevicePriority, masterDeviceID,
+         timelineID, newEPStr);
+
+    if (mTimelineID != timelineID) {
+        // start following a new timeline
+        mTimelineID = timelineID;
+        mClockRecovery.reset(true, true);
+        notifyClockSyncLoss();
+    } else {
+        // start following a new master on the existing timeline
+        mClockRecovery.reset(false, true);
+    }
+
+    mMasterEP = masterEP;
+    mMasterEPValid = true;
+    setForceLowPriority(false);
+
+    mClient_MasterDeviceID = masterDeviceID;
+    mClient_MasterDevicePriority = masterDevicePriority;
+    resetSyncStats();
+
+    setState(ICommonClock::STATE_CLIENT);
+
+    // add some jitter to when the various clients send their requests
+    // in order to reduce the likelihood that a group of clients overload
+    // the master after receiving a master announcement
+    usleep((lrand48() % 100) * 1000);
+
+    return sendSyncRequest();
+}
+
+bool CommonTimeServer::becomeMaster(const char* cause) {
+    uint64_t oldTimelineID = mTimelineID;
+    if (mTimelineID == ICommonClock::kInvalidTimelineID) {
+        // this device has not been following any existing timeline,
+        // so it will create a new timeline and declare itself master
+        assert(!mCommonClock.isValid());
+
+        // set the common time basis
+        mCommonClock.setBasis(mLocalClock.getLocalTime(), 0);
+
+        // assign an arbitrary timeline iD
+        assignTimelineID();
+
+        // notify listeners that we've created a common timeline
+        notifyClockSync();
+    }
+
+    ALOGI("%s --> MASTER (%s) : %s timeline %016llx",
+         stateToString(mState), cause,
+         (oldTimelineID == mTimelineID) ? "taking ownership of"
+                                        : "creating new",
+         mTimelineID);
+
+    memset(&mMasterEP, 0, sizeof(mMasterEP));
+    mMasterEPValid = false;
+    setForceLowPriority(false);
+    mClient_MasterDevicePriority = effectivePriority();
+    mClient_MasterDeviceID = mDeviceID;
+    mClockRecovery.reset(false, true);
+    resetSyncStats();
+
+    setState(ICommonClock::STATE_MASTER);
+    return sendMasterAnnouncement();
+}
+
+bool CommonTimeServer::becomeRonin(const char* cause) {
+    // If we were the client of a given timeline, but had never received even a
+    // single time sync packet, then we transition back to Initial instead of
+    // Ronin.  If we transition to Ronin and end up becoming the new Master, we
+    // will be unable to service requests for other clients because we never
+    // actually knew what time it was.  By going to initial, we ensure that
+    // other clients who know what time it is, but would lose master arbitration
+    // in the Ronin case, will step up and become the proper new master of the
+    // old timeline.
+
+    char oldEPStr[64];
+    sockaddrToString(mMasterEP, mMasterEPValid, oldEPStr, sizeof(oldEPStr));
+    memset(&mMasterEP, 0, sizeof(mMasterEP));
+    mMasterEPValid = false;
+
+    if (mCommonClock.isValid()) {
+        ALOGI("%s --> RONIN (%s) : lost track of previously valid timeline "
+             "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)",
+             stateToString(mState), cause,
+             mClient_MasterDevicePriority, mClient_MasterDeviceID,
+             mTimelineID, oldEPStr,
+             mClient_SyncsSentToCurMaster,
+             mClient_SyncRespsRXedFromCurMaster,
+             mClient_ExpiredSyncRespsRXedFromCurMaster);
+
+        mRonin_WhoIsMasterRequestTimeouts = 0;
+        setState(ICommonClock::STATE_RONIN);
+        return sendWhoIsMasterRequest();
+    } else {
+        ALOGI("%s --> INITIAL (%s) : never synced timeline "
+             "%02x-%014llx::%016llx::%s (%d TXed %d RXed %d RXExpired)",
+             stateToString(mState), cause,
+             mClient_MasterDevicePriority, mClient_MasterDeviceID,
+             mTimelineID, oldEPStr,
+             mClient_SyncsSentToCurMaster,
+             mClient_SyncRespsRXedFromCurMaster,
+             mClient_ExpiredSyncRespsRXedFromCurMaster);
+
+        return becomeInitial("ronin, no timeline");
+    }
+}
+
+bool CommonTimeServer::becomeWaitForElection(const char* cause) {
+    ALOGI("%s --> WAIT_FOR_ELECTION (%s) : dropping out of election,"
+         " waiting %d mSec for completion.",
+         stateToString(mState), cause, kWaitForElection_TimeoutMs);
+
+    setState(ICommonClock::STATE_WAIT_FOR_ELECTION);
+    mCurTimeout.setTimeout(kWaitForElection_TimeoutMs);
+    return true;
+}
+
+bool CommonTimeServer::becomeInitial(const char* cause) {
+    ALOGI("Entering INITIAL (%s), total reset.", cause);
+
+    setState(ICommonClock::STATE_INITIAL);
+
+    // reset clock recovery
+    mClockRecovery.reset(true, true);
+
+    // reset internal state bookkeeping.
+    mCurTimeout.setTimeout(kInfiniteTimeout);
+    memset(&mMasterEP, 0, sizeof(mMasterEP));
+    mMasterEPValid = false;
+    mLastPacketRxLocalTime = 0;
+    mTimelineID = ICommonClock::kInvalidTimelineID;
+    mClockSynced = false;
+    mInitial_WhoIsMasterRequestTimeouts = 0;
+    mClient_MasterDeviceID = 0;
+    mClient_MasterDevicePriority = 0;
+    mRonin_WhoIsMasterRequestTimeouts = 0;
+    resetSyncStats();
+
+    // send the first request to discover the master
+    return sendWhoIsMasterRequest();
+}
+
+void CommonTimeServer::notifyClockSync() {
+    if (!mClockSynced) {
+        mClockSynced = true;
+        mICommonClock->notifyOnTimelineChanged(mTimelineID);
+    }
+}
+
+void CommonTimeServer::notifyClockSyncLoss() {
+    if (mClockSynced) {
+        mClockSynced = false;
+        mICommonClock->notifyOnTimelineChanged(
+                ICommonClock::kInvalidTimelineID);
+    }
+}
+
+void CommonTimeServer::setState(ICommonClock::State s) {
+    mState = s;
+}
+
+const char* CommonTimeServer::stateToString(ICommonClock::State s) {
+    switch(s) {
+        case ICommonClock::STATE_INITIAL:
+            return "INITIAL";
+        case ICommonClock::STATE_CLIENT:
+            return "CLIENT";
+        case ICommonClock::STATE_MASTER:
+            return "MASTER";
+        case ICommonClock::STATE_RONIN:
+            return "RONIN";
+        case ICommonClock::STATE_WAIT_FOR_ELECTION:
+            return "WAIT_FOR_ELECTION";
+        default:
+            return "unknown";
+    }
+}
+
+void CommonTimeServer::sockaddrToString(const sockaddr_storage& addr,
+                                        bool addrValid,
+                                        char* buf, size_t bufLen) {
+    if (!bufLen || !buf)
+        return;
+
+    if (addrValid) {
+        switch (addr.ss_family) {
+            case AF_INET: {
+                const struct sockaddr_in* sa =
+                    reinterpret_cast<const struct sockaddr_in*>(&addr);
+                unsigned long a = ntohl(sa->sin_addr.s_addr);
+                uint16_t      p = ntohs(sa->sin_port);
+                snprintf(buf, bufLen, "%lu.%lu.%lu.%lu:%hu",
+                        ((a >> 24) & 0xFF), ((a >> 16) & 0xFF),
+                        ((a >>  8) & 0xFF),  (a        & 0xFF), p);
+            } break;
+
+            case AF_INET6: {
+                const struct sockaddr_in6* sa =
+                    reinterpret_cast<const struct sockaddr_in6*>(&addr);
+                const uint8_t* a = sa->sin6_addr.s6_addr;
+                uint16_t       p = ntohs(sa->sin6_port);
+                snprintf(buf, bufLen,
+                        "%02X%02X:%02X%02X:%02X%02X:%02X%02X:"
+                        "%02X%02X:%02X%02X:%02X%02X:%02X%02X port %hd",
+                        a[0], a[1], a[ 2], a[ 3], a[ 4], a[ 5], a[ 6], a[ 7],
+                        a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15],
+                        p);
+            } break;
+
+            default:
+                snprintf(buf, bufLen,
+                         "<unknown sockaddr family %d>", addr.ss_family);
+                break;
+        }
+    } else {
+        snprintf(buf, bufLen, "<none>");
+    }
+
+    buf[bufLen - 1] = 0;
+}
+
+bool CommonTimeServer::sockaddrMatch(const sockaddr_storage& a1,
+                                     const sockaddr_storage& a2,
+                                     bool matchAddressOnly) {
+    if (a1.ss_family != a2.ss_family)
+        return false;
+
+    switch (a1.ss_family) {
+        case AF_INET: {
+            const struct sockaddr_in* sa1 =
+                reinterpret_cast<const struct sockaddr_in*>(&a1);
+            const struct sockaddr_in* sa2 =
+                reinterpret_cast<const struct sockaddr_in*>(&a2);
+
+            if (sa1->sin_addr.s_addr != sa2->sin_addr.s_addr)
+                return false;
+
+            return (matchAddressOnly || (sa1->sin_port == sa2->sin_port));
+        } break;
+
+        case AF_INET6: {
+            const struct sockaddr_in6* sa1 =
+                reinterpret_cast<const struct sockaddr_in6*>(&a1);
+            const struct sockaddr_in6* sa2 =
+                reinterpret_cast<const struct sockaddr_in6*>(&a2);
+
+            if (memcmp(&sa1->sin6_addr, &sa2->sin6_addr, sizeof(sa2->sin6_addr)))
+                return false;
+
+            return (matchAddressOnly || (sa1->sin6_port == sa2->sin6_port));
+        } break;
+
+        // Huh?  We don't deal in non-IPv[46] addresses.  Not sure how we got
+        // here, but we don't know how to comapre these addresses and simply
+        // default to a no-match decision.
+        default: return false;
+    }
+}
+
+void CommonTimeServer::TimeoutHelper::setTimeout(int msec) {
+    mTimeoutValid = (msec >= 0);
+    if (mTimeoutValid)
+        mEndTime = systemTime() +
+                   (static_cast<nsecs_t>(msec) * 1000000);
+}
+
+int CommonTimeServer::TimeoutHelper::msecTillTimeout() {
+    if (!mTimeoutValid)
+        return kInfiniteTimeout;
+
+    nsecs_t now = systemTime();
+    if (now >= mEndTime)
+        return 0;
+
+    uint64_t deltaMsec = (((mEndTime - now) + 999999) / 1000000);
+
+    if (deltaMsec > static_cast<uint64_t>(MAX_INT))
+        return MAX_INT;
+
+    return static_cast<int>(deltaMsec);
+}
+
+bool CommonTimeServer::shouldPanicNotGettingGoodData() {
+    if (mClient_FirstSyncTX) {
+        int64_t now = mLocalClock.getLocalTime();
+        int64_t delta = now - (mClient_LastGoodSyncRX
+                             ? mClient_LastGoodSyncRX
+                             : mClient_FirstSyncTX);
+        int64_t deltaUsec = mCommonClock.localDurationToCommonDuration(delta);
+
+        if (deltaUsec >= kNoGoodDataPanicThresholdUsec)
+            return true;
+    }
+
+    return false;
+}
+
+void CommonTimeServer::PacketRTTLog::logTX(int64_t txTime) {
+    txTimes[wrPtr] = txTime;
+    rxTimes[wrPtr] = 0;
+    wrPtr = (wrPtr + 1) % RTT_LOG_SIZE;
+    if (!wrPtr)
+        logFull = true;
+}
+
+void CommonTimeServer::PacketRTTLog::logRX(int64_t txTime, int64_t rxTime) {
+    if (!logFull && !wrPtr)
+        return;
+
+    uint32_t i = logFull ? wrPtr : 0;
+    do {
+        if (txTimes[i] == txTime) {
+            rxTimes[i] = rxTime;
+            break;
+        }
+        i = (i + 1) % RTT_LOG_SIZE;
+    } while (i != wrPtr);
+}
+
+}  // namespace android
diff --git a/services/common_time/common_time_server.h b/services/common_time/common_time_server.h
new file mode 100644
index 0000000..a0f549f
--- /dev/null
+++ b/services/common_time/common_time_server.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_COMMON_TIME_SERVER_H
+#define ANDROID_COMMON_TIME_SERVER_H
+
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <linux/socket.h>
+
+#include <common_time/ICommonClock.h>
+#include <common_time/local_clock.h>
+#include <utils/String8.h>
+
+#include "clock_recovery.h"
+#include "common_clock.h"
+#include "common_time_server_packets.h"
+
+#define RTT_LOG_SIZE 30
+
+namespace android {
+
+class CommonClockService;
+class CommonTimeConfigService;
+
+/***** time service implementation *****/
+
+class CommonTimeServer : public Thread {
+  public:
+    CommonTimeServer();
+    ~CommonTimeServer();
+
+    bool startServices();
+
+    // Common Clock API methods
+    CommonClock&        getCommonClock()        { return mCommonClock; }
+    LocalClock&         getLocalClock()         { return mLocalClock; }
+    uint64_t            getTimelineID();
+    int32_t             getEstimatedError();
+    ICommonClock::State getState();
+    status_t            getMasterAddr(struct sockaddr_storage* addr);
+    status_t            isCommonTimeValid(bool* valid, uint32_t* timelineID);
+
+    // Config API methods
+    status_t getMasterElectionPriority(uint8_t *priority);
+    status_t setMasterElectionPriority(uint8_t priority);
+    status_t getMasterElectionEndpoint(struct sockaddr_storage *addr);
+    status_t setMasterElectionEndpoint(const struct sockaddr_storage *addr);
+    status_t getMasterElectionGroupId(uint64_t *id);
+    status_t setMasterElectionGroupId(uint64_t id);
+    status_t getInterfaceBinding(String8& ifaceName);
+    status_t setInterfaceBinding(const String8& ifaceName);
+    status_t getMasterAnnounceInterval(int *interval);
+    status_t setMasterAnnounceInterval(int interval);
+    status_t getClientSyncInterval(int *interval);
+    status_t setClientSyncInterval(int interval);
+    status_t getPanicThreshold(int *threshold);
+    status_t setPanicThreshold(int threshold);
+    status_t getAutoDisable(bool *autoDisable);
+    status_t setAutoDisable(bool autoDisable);
+    status_t forceNetworklessMasterMode();
+
+    // Method used by the CommonClockService to notify the core service about
+    // changes in the number of active common clock clients.
+    void reevaluateAutoDisableState(bool commonClockHasClients);
+
+    status_t dumpClockInterface(int fd, const Vector<String16>& args,
+                                size_t activeClients);
+    status_t dumpConfigInterface(int fd, const Vector<String16>& args);
+
+  private:
+    class PacketRTTLog {
+      public:
+        PacketRTTLog() {
+            resetLog();
+        }
+
+        void resetLog() {
+            wrPtr = 0;
+            logFull = 0;
+        }
+
+        void logTX(int64_t txTime);
+        void logRX(int64_t txTime, int64_t rxTime);
+        void dumpLog(int fd, const CommonClock& cclk);
+
+      private:
+        uint32_t wrPtr;
+        bool logFull;
+        int64_t txTimes[RTT_LOG_SIZE];
+        int64_t rxTimes[RTT_LOG_SIZE];
+    };
+
+    class TimeoutHelper {
+      public:
+        TimeoutHelper() : mTimeoutValid(false) { }
+
+        void setTimeout(int msec);
+        int msecTillTimeout();
+
+      private:
+        bool        mTimeoutValid;
+        nsecs_t     mEndTime;
+    };
+
+    bool threadLoop();
+
+    bool runStateMachine_l();
+    bool setupSocket_l();
+
+    void assignTimelineID();
+    bool assignDeviceID();
+
+    static bool arbitrateMaster(uint64_t deviceID1, uint8_t devicePrio1,
+                                uint64_t deviceID2, uint8_t devicePrio2);
+
+    bool handlePacket();
+    bool handleWhoIsMasterRequest (const WhoIsMasterRequestPacket* request,
+                                   const sockaddr_storage& srcAddr);
+    bool handleWhoIsMasterResponse(const WhoIsMasterResponsePacket* response,
+                                   const sockaddr_storage& srcAddr);
+    bool handleSyncRequest        (const SyncRequestPacket* request,
+                                   const sockaddr_storage& srcAddr);
+    bool handleSyncResponse       (const SyncResponsePacket* response,
+                                   const sockaddr_storage& srcAddr);
+    bool handleMasterAnnouncement (const MasterAnnouncementPacket* packet,
+                                   const sockaddr_storage& srcAddr);
+
+    bool handleTimeout();
+    bool handleTimeoutInitial();
+    bool handleTimeoutClient();
+    bool handleTimeoutMaster();
+    bool handleTimeoutRonin();
+    bool handleTimeoutWaitForElection();
+
+    bool sendWhoIsMasterRequest();
+    bool sendSyncRequest();
+    bool sendMasterAnnouncement();
+
+    bool becomeClient(const sockaddr_storage& masterAddr,
+                      uint64_t masterDeviceID,
+                      uint8_t  masterDevicePriority,
+                      uint64_t timelineID,
+                      const char* cause);
+    bool becomeMaster(const char* cause);
+    bool becomeRonin(const char* cause);
+    bool becomeWaitForElection(const char* cause);
+    bool becomeInitial(const char* cause);
+
+    void notifyClockSync();
+    void notifyClockSyncLoss();
+
+    ICommonClock::State mState;
+    void setState(ICommonClock::State s);
+
+    void clearPendingWakeupEvents_l();
+    void wakeupThread_l();
+    void cleanupSocket_l();
+    void shutdownThread();
+
+    inline uint8_t effectivePriority() const {
+        return (mMasterPriority & 0x7F) |
+               (mForceLowPriority ? 0x00 : 0x80);
+    }
+
+    inline bool shouldAutoDisable() const {
+        return (mAutoDisable && !mCommonClockHasClients);
+    }
+
+    inline void resetSyncStats() {
+        mClient_SyncRequestPending = false;
+        mClient_SyncRequestTimeouts = 0;
+        mClient_SyncsSentToCurMaster = 0;
+        mClient_SyncRespsRXedFromCurMaster = 0;
+        mClient_ExpiredSyncRespsRXedFromCurMaster = 0;
+        mClient_FirstSyncTX = 0;
+        mClient_LastGoodSyncRX = 0;
+        mClient_PacketRTTLog.resetLog();
+    }
+
+    bool shouldPanicNotGettingGoodData();
+
+    // Helper to keep track of the state machine's current timeout
+    TimeoutHelper mCurTimeout;
+
+    // common clock, local clock abstraction, and clock recovery loop
+    CommonClock mCommonClock;
+    LocalClock mLocalClock;
+    ClockRecoveryLoop mClockRecovery;
+
+    // implementation of ICommonClock
+    sp<CommonClockService> mICommonClock;
+
+    // implementation of ICommonTimeConfig
+    sp<CommonTimeConfigService> mICommonTimeConfig;
+
+    // UDP socket for the time sync protocol
+    int mSocket;
+
+    // eventfd used to wakeup the work thread in response to configuration
+    // changes.
+    int mWakeupThreadFD;
+
+    // timestamp captured when a packet is received
+    int64_t mLastPacketRxLocalTime;
+
+    // ID of the timeline that this device is following
+    uint64_t mTimelineID;
+
+    // flag for whether the clock has been synced to a timeline
+    bool mClockSynced;
+
+    // flag used to indicate that clients should be considered to be lower
+    // priority than all of their peers during elections.  This flag is set and
+    // cleared by the state machine.  It is set when the client joins a new
+    // network.  If the client had been a master in the old network (or an
+    // isolated master with no network connectivity) it should defer to any
+    // masters which may already be on the network.  It will be cleared whenever
+    // the state machine transitions to the master state.
+    bool mForceLowPriority;
+    inline void setForceLowPriority(bool val) {
+        mForceLowPriority = val;
+        if (mState == ICommonClock::STATE_MASTER)
+            mClient_MasterDevicePriority = effectivePriority();
+    }
+
+    // Lock to synchronize access to internal state and configuration.
+    Mutex mLock;
+
+    // Flag updated by the common clock service to indicate that it does or does
+    // not currently have registered clients.  When the the auto disable flag is
+    // cleared on the common time service, the service will participate in
+    // network synchronization whenever it has a valid network interface to bind
+    // to.  When the auto disable flag is set on the common time service, it
+    // will only participate in network synchronization when it has both a valid
+    // interface AND currently active common clock clients.
+    bool mCommonClockHasClients;
+
+    // Configuration info
+    struct sockaddr_storage mMasterElectionEP;          // Endpoint over which we conduct master election
+    String8                 mBindIface;                 // Endpoint for the service to bind to.
+    bool                    mBindIfaceValid;            // whether or not the bind Iface is valid.
+    bool                    mBindIfaceDirty;            // whether or not the bind Iface is valid.
+    struct sockaddr_storage mMasterEP;                  // Endpoint of our current master (if any)
+    bool                    mMasterEPValid;
+    uint64_t                mDeviceID;                  // unique ID of this device
+    uint64_t                mSyncGroupID;               // synchronization group ID of this device.
+    uint8_t                 mMasterPriority;            // Priority of this device in master election.
+    uint32_t                mMasterAnnounceIntervalMs;
+    uint32_t                mSyncRequestIntervalMs;
+    uint32_t                mPanicThresholdUsec;
+    bool                    mAutoDisable;
+
+    // Config defaults.
+    static const char*      kDefaultMasterElectionAddr;
+    static const uint16_t   kDefaultMasterElectionPort;
+    static const uint64_t   kDefaultSyncGroupID;
+    static const uint8_t    kDefaultMasterPriority;
+    static const uint32_t   kDefaultMasterAnnounceIntervalMs;
+    static const uint32_t   kDefaultSyncRequestIntervalMs;
+    static const uint32_t   kDefaultPanicThresholdUsec;
+    static const bool       kDefaultAutoDisable;
+
+    // Priority mask and shift fields.
+    static const uint64_t kDeviceIDMask;
+    static const uint8_t  kDevicePriorityMask;
+    static const uint8_t  kDevicePriorityHiLowBit;
+    static const uint32_t kDevicePriorityShift;
+
+    // Unconfgurable constants
+    static const int      kSetupRetryTimeoutMs;
+    static const int64_t  kNoGoodDataPanicThresholdUsec;
+    static const uint32_t kRTTDiscardPanicThreshMultiplier;
+
+    /*** status while in the Initial state ***/
+    int mInitial_WhoIsMasterRequestTimeouts;
+    static const int kInitial_NumWhoIsMasterRetries;
+    static const int kInitial_WhoIsMasterTimeoutMs;
+
+    /*** status while in the Client state ***/
+    uint64_t mClient_MasterDeviceID;
+    uint8_t mClient_MasterDevicePriority;
+    bool mClient_SyncRequestPending;
+    int mClient_SyncRequestTimeouts;
+    uint32_t mClient_SyncsSentToCurMaster;
+    uint32_t mClient_SyncRespsRXedFromCurMaster;
+    uint32_t mClient_ExpiredSyncRespsRXedFromCurMaster;
+    int64_t mClient_FirstSyncTX;
+    int64_t mClient_LastGoodSyncRX;
+    PacketRTTLog mClient_PacketRTTLog;
+    static const int kClient_NumSyncRequestRetries;
+
+
+    /*** status while in the Master state ***/
+    static const uint32_t kDefaultMaster_AnnouncementIntervalMs;
+
+    /*** status while in the Ronin state ***/
+    int mRonin_WhoIsMasterRequestTimeouts;
+    static const int kRonin_NumWhoIsMasterRetries;
+    static const int kRonin_WhoIsMasterTimeoutMs;
+
+    /*** status while in the WaitForElection state ***/
+    static const int kWaitForElection_TimeoutMs;
+
+    static const int kInfiniteTimeout;
+
+    static const char* stateToString(ICommonClock::State s);
+    static void sockaddrToString(const sockaddr_storage& addr, bool addrValid,
+                                 char* buf, size_t bufLen);
+    static bool sockaddrMatch(const sockaddr_storage& a1,
+                              const sockaddr_storage& a2,
+                              bool matchAddressOnly);
+};
+
+}  // namespace android
+
+#endif  // ANDROID_COMMON_TIME_SERVER_H
diff --git a/services/common_time/common_time_server_api.cpp b/services/common_time/common_time_server_api.cpp
new file mode 100644
index 0000000..fb8c261
--- /dev/null
+++ b/services/common_time/common_time_server_api.cpp
@@ -0,0 +1,435 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
+
+#include "common_time_server.h"
+
+namespace android {
+
+//
+// Clock API
+//
+uint64_t CommonTimeServer::getTimelineID() {
+    AutoMutex _lock(&mLock);
+    return mTimelineID;
+}
+
+ICommonClock::State CommonTimeServer::getState() {
+    AutoMutex _lock(&mLock);
+    return mState;
+}
+
+status_t CommonTimeServer::getMasterAddr(struct sockaddr_storage* addr) {
+    AutoMutex _lock(&mLock);
+    if (mMasterEPValid) {
+        memcpy(addr, &mMasterEP, sizeof(*addr));
+        return OK;
+    }
+
+    return UNKNOWN_ERROR;
+}
+
+int32_t CommonTimeServer::getEstimatedError() {
+    AutoMutex _lock(&mLock);
+
+    if (ICommonClock::STATE_MASTER == mState)
+        return 0;
+
+    if (!mClockSynced)
+        return ICommonClock::kErrorEstimateUnknown;
+
+    return mClockRecovery.getLastErrorEstimate();
+}
+
+status_t CommonTimeServer::isCommonTimeValid(bool* valid,
+                                             uint32_t* timelineID) {
+    AutoMutex _lock(&mLock);
+    *valid = mCommonClock.isValid();
+    *timelineID = mTimelineID;
+    return OK;
+}
+
+//
+// Config API
+//
+status_t CommonTimeServer::getMasterElectionPriority(uint8_t *priority) {
+    AutoMutex _lock(&mLock);
+    *priority = mMasterPriority;
+    return OK;
+}
+
+status_t CommonTimeServer::setMasterElectionPriority(uint8_t priority) {
+    AutoMutex _lock(&mLock);
+
+    if (priority > 0x7F)
+        return BAD_VALUE;
+
+    mMasterPriority = priority;
+    return OK;
+}
+
+status_t CommonTimeServer::getMasterElectionEndpoint(
+        struct sockaddr_storage *addr) {
+    AutoMutex _lock(&mLock);
+    memcpy(addr, &mMasterElectionEP, sizeof(*addr));
+    return OK;
+}
+
+status_t CommonTimeServer::setMasterElectionEndpoint(
+        const struct sockaddr_storage *addr) {
+    AutoMutex _lock(&mLock);
+
+    if (!addr)
+        return BAD_VALUE;
+
+    // TODO: add proper support for IPv6
+    if (addr->ss_family != AF_INET)
+        return BAD_VALUE;
+
+    // Only multicast and broadcast endpoints with explicit ports are allowed.
+    uint16_t ipv4Port = ntohs(
+        reinterpret_cast<const struct sockaddr_in*>(addr)->sin_port);
+    if (!ipv4Port)
+        return BAD_VALUE;
+
+    uint32_t ipv4Addr = ntohl(
+        reinterpret_cast<const struct sockaddr_in*>(addr)->sin_addr.s_addr);
+    if ((ipv4Addr != 0xFFFFFFFF) && (0xE0000000 != (ipv4Addr & 0xF0000000)))
+        return BAD_VALUE;
+
+    memcpy(&mMasterElectionEP, addr, sizeof(mMasterElectionEP));
+
+    // Force a rebind in order to change election enpoints.
+    mBindIfaceDirty = true;
+    wakeupThread_l();
+    return OK;
+}
+
+status_t CommonTimeServer::getMasterElectionGroupId(uint64_t *id) {
+    AutoMutex _lock(&mLock);
+    *id = mSyncGroupID;
+    return OK;
+}
+
+status_t CommonTimeServer::setMasterElectionGroupId(uint64_t id) {
+    AutoMutex _lock(&mLock);
+    mSyncGroupID = id;
+    return OK;
+}
+
+status_t CommonTimeServer::getInterfaceBinding(String8& ifaceName) {
+    AutoMutex _lock(&mLock);
+    if (!mBindIfaceValid)
+        return INVALID_OPERATION;
+    ifaceName = mBindIface;
+    return OK;
+}
+
+status_t CommonTimeServer::setInterfaceBinding(const String8& ifaceName) {
+    AutoMutex _lock(&mLock);
+
+    mBindIfaceDirty = true;
+    if (ifaceName.size()) {
+        mBindIfaceValid = true;
+        mBindIface = ifaceName;
+    } else {
+        mBindIfaceValid = false;
+        mBindIface.clear();
+    }
+
+    wakeupThread_l();
+    return OK;
+}
+
+status_t CommonTimeServer::getMasterAnnounceInterval(int *interval) {
+    AutoMutex _lock(&mLock);
+    *interval = mMasterAnnounceIntervalMs;
+    return OK;
+}
+
+status_t CommonTimeServer::setMasterAnnounceInterval(int interval) {
+    AutoMutex _lock(&mLock);
+
+    if (interval > (6 *3600000)) // Max interval is once every 6 hrs
+        return BAD_VALUE;
+
+    if (interval < 500) // Min interval is once per 0.5 seconds
+        return BAD_VALUE;
+
+    mMasterAnnounceIntervalMs = interval;
+    if (ICommonClock::STATE_MASTER == mState) {
+        int pendingTimeout = mCurTimeout.msecTillTimeout();
+        if ((kInfiniteTimeout == pendingTimeout) ||
+            (pendingTimeout > interval)) {
+            mCurTimeout.setTimeout(mMasterAnnounceIntervalMs);
+            wakeupThread_l();
+        }
+    }
+
+    return OK;
+}
+
+status_t CommonTimeServer::getClientSyncInterval(int *interval) {
+    AutoMutex _lock(&mLock);
+    *interval = mSyncRequestIntervalMs;
+    return OK;
+}
+
+status_t CommonTimeServer::setClientSyncInterval(int interval) {
+    AutoMutex _lock(&mLock);
+
+    if (interval > (3600000)) // Max interval is once every 60 min
+        return BAD_VALUE;
+
+    if (interval < 250) // Min interval is once per 0.25 seconds
+        return BAD_VALUE;
+
+    mSyncRequestIntervalMs = interval;
+    if (ICommonClock::STATE_CLIENT == mState) {
+        int pendingTimeout = mCurTimeout.msecTillTimeout();
+        if ((kInfiniteTimeout == pendingTimeout) ||
+            (pendingTimeout > interval)) {
+            mCurTimeout.setTimeout(mSyncRequestIntervalMs);
+            wakeupThread_l();
+        }
+    }
+
+    return OK;
+}
+
+status_t CommonTimeServer::getPanicThreshold(int *threshold) {
+    AutoMutex _lock(&mLock);
+    *threshold = mPanicThresholdUsec;
+    return OK;
+}
+
+status_t CommonTimeServer::setPanicThreshold(int threshold) {
+    AutoMutex _lock(&mLock);
+
+    if (threshold < 1000) // Min threshold is 1mSec
+        return BAD_VALUE;
+
+    mPanicThresholdUsec = threshold;
+    return OK;
+}
+
+status_t CommonTimeServer::getAutoDisable(bool *autoDisable) {
+    AutoMutex _lock(&mLock);
+    *autoDisable = mAutoDisable;
+    return OK;
+}
+
+status_t CommonTimeServer::setAutoDisable(bool autoDisable) {
+    AutoMutex _lock(&mLock);
+    mAutoDisable = autoDisable;
+    wakeupThread_l();
+    return OK;
+}
+
+status_t CommonTimeServer::forceNetworklessMasterMode() {
+    AutoMutex _lock(&mLock);
+
+    // Can't force networkless master mode if we are currently bound to a
+    // network.
+    if (mSocket >= 0)
+        return INVALID_OPERATION;
+
+    becomeMaster("force networkless");
+
+    return OK;
+}
+
+void CommonTimeServer::reevaluateAutoDisableState(bool commonClockHasClients) {
+    AutoMutex _lock(&mLock);
+    bool needWakeup = (mAutoDisable && mMasterEPValid &&
+                      (commonClockHasClients != mCommonClockHasClients));
+
+    mCommonClockHasClients = commonClockHasClients;
+
+    if (needWakeup) {
+        ALOGI("Waking up service, auto-disable is engaged and service now has%s"
+             " clients", mCommonClockHasClients ? "" : " no");
+        wakeupThread_l();
+    }
+}
+
+#define dump_printf(a, b...) do {                 \
+    int res;                                      \
+    res = snprintf(buffer, sizeof(buffer), a, b); \
+    buffer[sizeof(buffer) - 1] = 0;               \
+    if (res > 0)                                  \
+        write(fd, buffer, res);                   \
+} while (0)
+#define checked_percentage(a, b) ((0 == b) ? 0.0f : ((100.0f * a) / b))
+
+status_t CommonTimeServer::dumpClockInterface(int fd,
+                                              const Vector<String16>& args,
+                                              size_t activeClients) {
+    AutoMutex _lock(&mLock);
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: "
+                 "can't dump CommonClockService from pid=%d, uid=%d\n",
+                 IPCThreadState::self()->getCallingPid(),
+                 IPCThreadState::self()->getCallingUid());
+        write(fd, buffer, strlen(buffer));
+    } else {
+        int64_t commonTime;
+        int64_t localTime;
+        bool    synced;
+        char maStr[64];
+
+        localTime  = mLocalClock.getLocalTime();
+        synced     = (OK == mCommonClock.localToCommon(localTime, &commonTime));
+        sockaddrToString(mMasterEP, mMasterEPValid, maStr, sizeof(maStr));
+
+        dump_printf("Common Clock Service Status\nLocal time     : %lld\n",
+                    localTime);
+
+        if (synced)
+            dump_printf("Common time    : %lld\n", commonTime);
+        else
+            dump_printf("Common time    : %s\n", "not synced");
+
+        dump_printf("Timeline ID    : %016llx\n", mTimelineID);
+        dump_printf("State          : %s\n", stateToString(mState));
+        dump_printf("Master Addr    : %s\n", maStr);
+
+
+        if (synced) {
+            int32_t est = (ICommonClock::STATE_MASTER != mState)
+                        ? mClockRecovery.getLastErrorEstimate()
+                        : 0;
+            dump_printf("Error Est.     : %.3f msec\n",
+                        static_cast<float>(est) / 1000.0);
+        } else {
+            dump_printf("Error Est.     : %s\n", "unknown");
+        }
+
+        dump_printf("Syncs TXes     : %u\n", mClient_SyncsSentToCurMaster);
+        dump_printf("Syncs RXes     : %u (%.2f%%)\n",
+                    mClient_SyncRespsRXedFromCurMaster,
+                    checked_percentage(
+                        mClient_SyncRespsRXedFromCurMaster,
+                        mClient_SyncsSentToCurMaster));
+        dump_printf("RXs Expired    : %u (%.2f%%)\n",
+                    mClient_ExpiredSyncRespsRXedFromCurMaster,
+                    checked_percentage(
+                        mClient_ExpiredSyncRespsRXedFromCurMaster,
+                        mClient_SyncsSentToCurMaster));
+
+        if (!mClient_LastGoodSyncRX) {
+            dump_printf("Last Good RX   : %s\n", "unknown");
+        } else {
+            int64_t localDelta, usecDelta;
+            localDelta = localTime - mClient_LastGoodSyncRX;
+            usecDelta  = mCommonClock.localDurationToCommonDuration(localDelta);
+            dump_printf("Last Good RX   : %lld uSec ago\n", usecDelta);
+        }
+
+        dump_printf("Active Clients : %u\n", activeClients);
+        mClient_PacketRTTLog.dumpLog(fd, mCommonClock);
+    }
+
+    return NO_ERROR;
+}
+
+status_t CommonTimeServer::dumpConfigInterface(int fd,
+                                               const Vector<String16>& args) {
+    AutoMutex _lock(&mLock);
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+
+    if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
+        snprintf(buffer, SIZE, "Permission Denial: "
+                 "can't dump CommonTimeConfigService from pid=%d, uid=%d\n",
+                 IPCThreadState::self()->getCallingPid(),
+                 IPCThreadState::self()->getCallingUid());
+        write(fd, buffer, strlen(buffer));
+    } else {
+        char meStr[64];
+
+        sockaddrToString(mMasterElectionEP, true, meStr, sizeof(meStr));
+
+        dump_printf("Common Time Config Service Status\n"
+                    "Bound Interface           : %s\n",
+                    mBindIfaceValid ? mBindIface.string() : "<unbound>");
+        dump_printf("Master Election Endpoint  : %s\n", meStr);
+        dump_printf("Master Election Group ID  : %016llx\n", mSyncGroupID);
+        dump_printf("Master Announce Interval  : %d mSec\n",
+                    mMasterAnnounceIntervalMs);
+        dump_printf("Client Sync Interval      : %d mSec\n",
+                    mSyncRequestIntervalMs);
+        dump_printf("Panic Threshold           : %d uSec\n",
+                    mPanicThresholdUsec);
+        dump_printf("Base ME Prio              : 0x%02x\n",
+                    static_cast<uint32_t>(mMasterPriority));
+        dump_printf("Effective ME Prio         : 0x%02x\n",
+                    static_cast<uint32_t>(effectivePriority()));
+        dump_printf("Auto Disable Allowed      : %s\n",
+                    mAutoDisable ? "yes" : "no");
+        dump_printf("Auto Disable Engaged      : %s\n",
+                    shouldAutoDisable() ? "yes" : "no");
+    }
+
+    return NO_ERROR;
+}
+
+void CommonTimeServer::PacketRTTLog::dumpLog(int fd, const CommonClock& cclk) {
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    uint32_t avail = !logFull ? wrPtr : RTT_LOG_SIZE;
+
+    if (!avail)
+        return;
+
+    dump_printf("\nPacket Log (%d entries)\n", avail);
+
+    uint32_t ndx = 0;
+    uint32_t i = logFull ? wrPtr : 0;
+    do {
+        if (rxTimes[i]) {
+            int64_t delta = rxTimes[i] - txTimes[i];
+            int64_t deltaUsec = cclk.localDurationToCommonDuration(delta);
+            dump_printf("pkt[%2d] : localTX %12lld localRX %12lld "
+                        "(%.3f msec RTT)\n",
+                        ndx, txTimes[i], rxTimes[i],
+                        static_cast<float>(deltaUsec) / 1000.0);
+        } else {
+            dump_printf("pkt[%2d] : localTX %12lld localRX never\n",
+                        ndx, txTimes[i]);
+        }
+        i = (i + 1) % RTT_LOG_SIZE;
+        ndx++;
+    } while (i != wrPtr);
+}
+
+#undef dump_printf
+#undef checked_percentage
+
+}  // namespace android
diff --git a/services/common_time/common_time_server_packets.cpp b/services/common_time/common_time_server_packets.cpp
new file mode 100644
index 0000000..9833c37
--- /dev/null
+++ b/services/common_time/common_time_server_packets.cpp
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <arpa/inet.h>
+#include <stdint.h>
+
+#include "common_time_server_packets.h"
+
+namespace android {
+
+const uint32_t TimeServicePacketHeader::kMagic =
+    (static_cast<uint32_t>('c') << 24) |
+    (static_cast<uint32_t>('c') << 16) |
+    (static_cast<uint32_t>('l') <<  8) |
+     static_cast<uint32_t>('k');
+
+const uint16_t TimeServicePacketHeader::kCurVersion = 1;
+
+#define SERIALIZE_FIELD(field_name, type, converter)        \
+    do {                                                    \
+        if ((offset + sizeof(field_name)) > length)         \
+            return -1;                                      \
+        *((type*)(data + offset)) = converter(field_name);  \
+        offset += sizeof(field_name);                       \
+    } while (0)
+#define SERIALIZE_INT16(field_name) SERIALIZE_FIELD(field_name, int16_t, htons)
+#define SERIALIZE_INT32(field_name) SERIALIZE_FIELD(field_name, int32_t, htonl)
+#define SERIALIZE_INT64(field_name) SERIALIZE_FIELD(field_name, int64_t, htonq)
+
+#define DESERIALIZE_FIELD(field_name, type, converter)      \
+    do {                                                    \
+        if ((offset + sizeof(field_name)) > length)         \
+            return -1;                                      \
+        field_name = converter(*((type*)(data + offset)));  \
+        offset += sizeof(field_name);                       \
+    } while (0)
+#define DESERIALIZE_INT16(field_name) DESERIALIZE_FIELD(field_name, int16_t, ntohs)
+#define DESERIALIZE_INT32(field_name) DESERIALIZE_FIELD(field_name, int32_t, ntohl)
+#define DESERIALIZE_INT64(field_name) DESERIALIZE_FIELD(field_name, int64_t, ntohq)
+
+#define kDevicePriorityShift 56
+#define kDeviceIDMask ((static_cast<uint64_t>(1) << kDevicePriorityShift) - 1)
+
+inline uint64_t packDeviceID(uint64_t devID, uint8_t prio) {
+    return (devID & kDeviceIDMask) |
+           (static_cast<uint64_t>(prio) << kDevicePriorityShift);
+}
+
+inline uint64_t unpackDeviceID(uint64_t packed) {
+    return (packed & kDeviceIDMask);
+}
+
+inline uint8_t unpackDevicePriority(uint64_t packed) {
+    return static_cast<uint8_t>(packed >> kDevicePriorityShift);
+}
+
+ssize_t TimeServicePacketHeader::serializeHeader(uint8_t* data,
+                                                 uint32_t length) {
+    ssize_t offset = 0;
+    int16_t pktType = static_cast<int16_t>(packetType);
+    SERIALIZE_INT32(magic);
+    SERIALIZE_INT16(version);
+    SERIALIZE_INT16(pktType);
+    SERIALIZE_INT64(timelineID);
+    SERIALIZE_INT64(syncGroupID);
+    return offset;
+}
+
+ssize_t TimeServicePacketHeader::deserializeHeader(const uint8_t* data,
+                                                   uint32_t length) {
+    ssize_t offset = 0;
+    int16_t tmp;
+    DESERIALIZE_INT32(magic);
+    DESERIALIZE_INT16(version);
+    DESERIALIZE_INT16(tmp);
+    DESERIALIZE_INT64(timelineID);
+    DESERIALIZE_INT64(syncGroupID);
+    packetType = static_cast<TimeServicePacketType>(tmp);
+    return offset;
+}
+
+ssize_t TimeServicePacketHeader::serializePacket(uint8_t* data,
+                                                 uint32_t length) {
+    ssize_t ret, tmp;
+
+    ret = serializeHeader(data, length);
+    if (ret < 0)
+        return ret;
+
+    data += ret;
+    length -= ret;
+
+    switch (packetType) {
+        case TIME_PACKET_WHO_IS_MASTER_REQUEST:
+            tmp =((WhoIsMasterRequestPacket*)(this))->serializePacket(data,
+                                                                      length);
+            break;
+        case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
+            tmp =((WhoIsMasterResponsePacket*)(this))->serializePacket(data,
+                                                                       length);
+            break;
+        case TIME_PACKET_SYNC_REQUEST:
+            tmp =((SyncRequestPacket*)(this))->serializePacket(data, length);
+            break;
+        case TIME_PACKET_SYNC_RESPONSE:
+            tmp =((SyncResponsePacket*)(this))->serializePacket(data, length);
+            break;
+        case TIME_PACKET_MASTER_ANNOUNCEMENT:
+            tmp =((MasterAnnouncementPacket*)(this))->serializePacket(data,
+                                                                      length);
+            break;
+        default:
+            return -1;
+    }
+
+    if (tmp < 0)
+        return tmp;
+
+    return ret + tmp;
+}
+
+ssize_t UniversalTimeServicePacket::deserializePacket(
+        const uint8_t* data,
+        uint32_t length,
+        uint64_t expectedSyncGroupID) {
+    ssize_t ret;
+    TimeServicePacketHeader* header;
+    if (length < 8)
+        return -1;
+
+    packetType = ntohs(*((uint16_t*)(data + 6)));
+    switch (packetType) {
+        case TIME_PACKET_WHO_IS_MASTER_REQUEST:
+            ret = p.who_is_master_request.deserializePacket(data, length);
+            header = &p.who_is_master_request;
+            break;
+        case TIME_PACKET_WHO_IS_MASTER_RESPONSE:
+            ret = p.who_is_master_response.deserializePacket(data, length);
+            header = &p.who_is_master_response;
+            break;
+        case TIME_PACKET_SYNC_REQUEST:
+            ret = p.sync_request.deserializePacket(data, length);
+            header = &p.sync_request;
+            break;
+        case TIME_PACKET_SYNC_RESPONSE:
+            ret = p.sync_response.deserializePacket(data, length);
+            header = &p.sync_response;
+            break;
+        case TIME_PACKET_MASTER_ANNOUNCEMENT:
+            ret = p.master_announcement.deserializePacket(data, length);
+            header = &p.master_announcement;
+            break;
+        default:
+            return -1;
+    }
+
+    if ((ret >= 0) && !header->checkPacket(expectedSyncGroupID))
+        ret = -1;
+
+    return ret;
+}
+
+ssize_t WhoIsMasterRequestPacket::serializePacket(uint8_t* data,
+                                                  uint32_t length) {
+    ssize_t offset = serializeHeader(data, length);
+    if (offset > 0) {
+        uint64_t packed = packDeviceID(senderDeviceID, senderDevicePriority);
+        SERIALIZE_INT64(packed);
+    }
+    return offset;
+}
+
+ssize_t WhoIsMasterRequestPacket::deserializePacket(const uint8_t* data,
+                                                    uint32_t length) {
+    ssize_t offset = deserializeHeader(data, length);
+    if (offset > 0) {
+        uint64_t packed;
+        DESERIALIZE_INT64(packed);
+        senderDeviceID       = unpackDeviceID(packed);
+        senderDevicePriority = unpackDevicePriority(packed);
+    }
+    return offset;
+}
+
+ssize_t WhoIsMasterResponsePacket::serializePacket(uint8_t* data,
+                                                   uint32_t length) {
+    ssize_t offset = serializeHeader(data, length);
+    if (offset > 0) {
+        uint64_t packed = packDeviceID(deviceID, devicePriority);
+        SERIALIZE_INT64(packed);
+    }
+    return offset;
+}
+
+ssize_t WhoIsMasterResponsePacket::deserializePacket(const uint8_t* data,
+                                                     uint32_t length) {
+    ssize_t offset = deserializeHeader(data, length);
+    if (offset > 0) {
+        uint64_t packed;
+        DESERIALIZE_INT64(packed);
+        deviceID       = unpackDeviceID(packed);
+        devicePriority = unpackDevicePriority(packed);
+    }
+    return offset;
+}
+
+ssize_t SyncRequestPacket::serializePacket(uint8_t* data,
+                                           uint32_t length) {
+    ssize_t offset = serializeHeader(data, length);
+    if (offset > 0) {
+        SERIALIZE_INT64(clientTxLocalTime);
+    }
+    return offset;
+}
+
+ssize_t SyncRequestPacket::deserializePacket(const uint8_t* data,
+                                             uint32_t length) {
+    ssize_t offset = deserializeHeader(data, length);
+    if (offset > 0) {
+        DESERIALIZE_INT64(clientTxLocalTime);
+    }
+    return offset;
+}
+
+ssize_t SyncResponsePacket::serializePacket(uint8_t* data,
+                                            uint32_t length) {
+    ssize_t offset = serializeHeader(data, length);
+    if (offset > 0) {
+        SERIALIZE_INT64(clientTxLocalTime);
+        SERIALIZE_INT64(masterRxCommonTime);
+        SERIALIZE_INT64(masterTxCommonTime);
+        SERIALIZE_INT32(nak);
+    }
+    return offset;
+}
+
+ssize_t SyncResponsePacket::deserializePacket(const uint8_t* data,
+                                              uint32_t length) {
+    ssize_t offset = deserializeHeader(data, length);
+    if (offset > 0) {
+        DESERIALIZE_INT64(clientTxLocalTime);
+        DESERIALIZE_INT64(masterRxCommonTime);
+        DESERIALIZE_INT64(masterTxCommonTime);
+        DESERIALIZE_INT32(nak);
+    }
+    return offset;
+}
+
+ssize_t MasterAnnouncementPacket::serializePacket(uint8_t* data,
+                                                  uint32_t length) {
+    ssize_t offset = serializeHeader(data, length);
+    if (offset > 0) {
+        uint64_t packed = packDeviceID(deviceID, devicePriority);
+        SERIALIZE_INT64(packed);
+    }
+    return offset;
+}
+
+ssize_t MasterAnnouncementPacket::deserializePacket(const uint8_t* data,
+                                                    uint32_t length) {
+    ssize_t offset = deserializeHeader(data, length);
+    if (offset > 0) {
+        uint64_t packed;
+        DESERIALIZE_INT64(packed);
+        deviceID       = unpackDeviceID(packed);
+        devicePriority = unpackDevicePriority(packed);
+    }
+    return offset;
+}
+
+}  // namespace android
+
diff --git a/services/common_time/common_time_server_packets.h b/services/common_time/common_time_server_packets.h
new file mode 100644
index 0000000..57ba8a2
--- /dev/null
+++ b/services/common_time/common_time_server_packets.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_COMMON_TIME_SERVER_PACKETS_H
+#define ANDROID_COMMON_TIME_SERVER_PACKETS_H
+
+#include <stdint.h>
+#include <common_time/ICommonClock.h>
+
+namespace android {
+
+/***** time sync protocol packets *****/
+
+enum TimeServicePacketType {
+    TIME_PACKET_WHO_IS_MASTER_REQUEST = 1,
+    TIME_PACKET_WHO_IS_MASTER_RESPONSE,
+    TIME_PACKET_SYNC_REQUEST,
+    TIME_PACKET_SYNC_RESPONSE,
+    TIME_PACKET_MASTER_ANNOUNCEMENT,
+};
+
+class TimeServicePacketHeader {
+  public:
+    friend class UniversalTimeServicePacket;
+    // magic number identifying the protocol
+    uint32_t magic;
+
+    // protocol version of the packet
+    uint16_t version;
+
+    // type of the packet
+    TimeServicePacketType packetType;
+
+    // the timeline ID
+    uint64_t timelineID;
+
+    // synchronization group this packet belongs to (used to operate multiple
+    // synchronization domains which all use the same master election endpoint)
+    uint64_t syncGroupID;
+
+    ssize_t serializePacket(uint8_t* data, uint32_t length);
+
+  protected:
+    void initHeader(TimeServicePacketType type,
+                    const uint64_t tlID,
+                    const uint64_t groupID) {
+        magic              = kMagic;
+        version            = kCurVersion;
+        packetType         = type;
+        timelineID         = tlID;
+        syncGroupID        = groupID;
+    }
+
+    bool checkPacket(uint64_t expectedSyncGroupID) const {
+        return ((magic       == kMagic) &&
+                (version     == kCurVersion) &&
+                (!expectedSyncGroupID || (syncGroupID == expectedSyncGroupID)));
+    }
+
+    ssize_t serializeHeader(uint8_t* data, uint32_t length);
+    ssize_t deserializeHeader(const uint8_t* data, uint32_t length);
+
+  private:
+    static const uint32_t kMagic;
+    static const uint16_t kCurVersion;
+};
+
+// packet querying for a suitable master
+class WhoIsMasterRequestPacket : public TimeServicePacketHeader {
+  public:
+    uint64_t senderDeviceID;
+    uint8_t senderDevicePriority;
+
+    void initHeader(const uint64_t groupID) {
+        TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_REQUEST,
+                                            ICommonClock::kInvalidTimelineID,
+                                            groupID);
+    }
+
+    ssize_t serializePacket(uint8_t* data, uint32_t length);
+    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// response to a WhoIsMaster request
+class WhoIsMasterResponsePacket : public TimeServicePacketHeader {
+  public:
+    uint64_t deviceID;
+    uint8_t devicePriority;
+
+    void initHeader(const uint64_t tlID, const uint64_t groupID) {
+        TimeServicePacketHeader::initHeader(TIME_PACKET_WHO_IS_MASTER_RESPONSE,
+                                            tlID, groupID);
+    }
+
+    ssize_t serializePacket(uint8_t* data, uint32_t length);
+    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// packet sent by a client requesting correspondence between local
+// and common time
+class SyncRequestPacket : public TimeServicePacketHeader {
+  public:
+    // local time when this request was transmitted
+    int64_t clientTxLocalTime;
+
+    void initHeader(const uint64_t tlID, const uint64_t groupID) {
+        TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_REQUEST,
+                                            tlID, groupID);
+    }
+
+    ssize_t serializePacket(uint8_t* data, uint32_t length);
+    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// response to a sync request sent by the master
+class SyncResponsePacket : public TimeServicePacketHeader {
+  public:
+    // local time when this request was transmitted by the client
+    int64_t clientTxLocalTime;
+
+    // common time when the master received the request
+    int64_t masterRxCommonTime;
+
+    // common time when the master transmitted the response
+    int64_t masterTxCommonTime;
+
+    // flag that is set if the recipient of the sync request is not acting
+    // as a master for the requested timeline
+    uint32_t nak;
+
+    void initHeader(const uint64_t tlID, const uint64_t groupID) {
+        TimeServicePacketHeader::initHeader(TIME_PACKET_SYNC_RESPONSE,
+                                            tlID, groupID);
+    }
+
+    ssize_t serializePacket(uint8_t* data, uint32_t length);
+    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+// announcement of the master's presence
+class MasterAnnouncementPacket : public TimeServicePacketHeader {
+  public:
+    // the master's device ID
+    uint64_t deviceID;
+    uint8_t devicePriority;
+
+    void initHeader(const uint64_t tlID, const uint64_t groupID) {
+        TimeServicePacketHeader::initHeader(TIME_PACKET_MASTER_ANNOUNCEMENT,
+                                            tlID, groupID);
+    }
+
+    ssize_t serializePacket(uint8_t* data, uint32_t length);
+    ssize_t deserializePacket(const uint8_t* data, uint32_t length);
+};
+
+class UniversalTimeServicePacket {
+  public:
+    uint16_t packetType;
+    union {
+        WhoIsMasterRequestPacket  who_is_master_request;
+        WhoIsMasterResponsePacket who_is_master_response;
+        SyncRequestPacket         sync_request;
+        SyncResponsePacket        sync_response;
+        MasterAnnouncementPacket  master_announcement;
+    } p;
+
+    ssize_t deserializePacket(const uint8_t* data,
+                              uint32_t       length,
+                              uint64_t       expectedSyncGroupID);
+};
+
+};  // namespace android
+
+#endif  // ANDROID_COMMON_TIME_SERVER_PACKETS_H
+
+
diff --git a/services/common_time/diag_thread.cpp b/services/common_time/diag_thread.cpp
new file mode 100644
index 0000000..4cb9551
--- /dev/null
+++ b/services/common_time/diag_thread.cpp
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <fcntl.h>
+#include <linux/in.h>
+#include <linux/tcp.h>
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <utils/Errors.h>
+#include <utils/misc.h>
+
+#include <common_time/local_clock.h>
+
+#include "common_clock.h"
+#include "diag_thread.h"
+
+#define kMaxEvents 16
+#define kListenPort 9876
+
+static bool setNonblocking(int fd) {
+    int flags = fcntl(fd, F_GETFL);
+    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
+        ALOGE("Failed to set socket (%d) to non-blocking mode (errno %d)",
+             fd, errno);
+        return false;
+    }
+
+    return true;
+}
+
+static bool setNodelay(int fd) {
+    int tmp = 1;
+    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(tmp)) < 0) {
+        ALOGE("Failed to set socket (%d) to no-delay mode (errno %d)",
+             fd, errno);
+        return false;
+    }
+
+    return true;
+}
+
+namespace android {
+
+DiagThread::DiagThread(CommonClock* common_clock, LocalClock* local_clock) {
+    common_clock_ = common_clock;
+    local_clock_ = local_clock;
+    listen_fd_ = -1;
+    data_fd_ = -1;
+    kernel_logID_basis_known_ = false;
+    discipline_log_ID_ = 0;
+}
+
+DiagThread::~DiagThread() {
+}
+
+status_t DiagThread::startWorkThread() {
+    status_t res;
+    stopWorkThread();
+    res = run("Diag");
+
+    if (res != OK)
+        ALOGE("Failed to start work thread (res = %d)", res);
+
+    return res;
+}
+
+void DiagThread::stopWorkThread() {
+    status_t res;
+    res = requestExitAndWait(); // block until thread exit.
+    if (res != OK)
+        ALOGE("Failed to stop work thread (res = %d)", res);
+}
+
+bool DiagThread::openListenSocket() {
+    bool ret = false;
+    int flags;
+    cleanupListenSocket();
+
+    if ((listen_fd_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
+        ALOGE("Socket failed.");
+        goto bailout;
+    }
+
+    // Set non-blocking operation
+    if (!setNonblocking(listen_fd_))
+        goto bailout;
+
+    struct sockaddr_in addr;
+    memset(&addr, 0, sizeof(addr));
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = INADDR_ANY;
+    addr.sin_port = htons(kListenPort);
+
+    if (bind(listen_fd_, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
+        ALOGE("Bind failed.");
+        goto bailout;
+    }
+
+    if (listen(listen_fd_, 1) < 0) {
+        ALOGE("Listen failed.");
+        goto bailout;
+    }
+
+    ret = true;
+bailout:
+    if (!ret)
+        cleanupListenSocket();
+
+    return ret;
+}
+
+void DiagThread::cleanupListenSocket() {
+    if (listen_fd_ >= 0) {
+        int res;
+
+        struct linger l;
+        l.l_onoff  = 1;
+        l.l_linger = 0;
+
+        setsockopt(listen_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+        shutdown(listen_fd_, SHUT_RDWR);
+        close(listen_fd_);
+        listen_fd_ = -1;
+    }
+}
+
+void DiagThread::cleanupDataSocket() {
+    if (data_fd_ >= 0) {
+        int res;
+
+        struct linger l;
+        l.l_onoff  = 1;
+        l.l_linger = 0;
+
+        setsockopt(data_fd_, SOL_SOCKET, SO_LINGER, &l, sizeof(l));
+        shutdown(data_fd_, SHUT_RDWR);
+        close(data_fd_);
+        data_fd_ = -1;
+    }
+}
+
+void DiagThread::resetLogIDs() {
+    // Drain and discard all of the events from the kernel
+    struct local_time_debug_event events[kMaxEvents];
+    while(local_clock_->getDebugLog(events, kMaxEvents) > 0)
+        ;
+
+    {
+        Mutex::Autolock lock(&discipline_log_lock_);
+        discipline_log_.clear();
+        discipline_log_ID_ = 0;
+    }
+
+    kernel_logID_basis_known_ = false;
+}
+
+void DiagThread::pushDisciplineEvent(int64_t observed_local_time,
+                                     int64_t observed_common_time,
+                                     int64_t nominal_common_time,
+                                     int32_t total_correction,
+                                     int32_t rtt) {
+    Mutex::Autolock lock(&discipline_log_lock_);
+
+    DisciplineEventRecord evt;
+
+    evt.event_id = discipline_log_ID_++;
+
+    evt.action_local_time = local_clock_->getLocalTime();
+    common_clock_->localToCommon(evt.action_local_time,
+            &evt.action_common_time);
+
+    evt.observed_local_time  = observed_local_time;
+    evt.observed_common_time = observed_common_time;
+    evt.nominal_common_time  = nominal_common_time;
+    evt.total_correction     = total_correction;
+    evt.rtt                  = rtt;
+
+    discipline_log_.push_back(evt);
+    while (discipline_log_.size() > kMaxDisciplineLogSize)
+        discipline_log_.erase(discipline_log_.begin());
+}
+
+bool DiagThread::threadLoop() {
+    struct pollfd poll_fds[1];
+
+    if (!openListenSocket()) {
+        ALOGE("Failed to open listen socket");
+        goto bailout;
+    }
+
+    while (!exitPending()) {
+        memset(&poll_fds, 0, sizeof(poll_fds));
+
+        if (data_fd_ < 0) {
+            poll_fds[0].fd     = listen_fd_;
+            poll_fds[0].events = POLLIN;
+        } else {
+            poll_fds[0].fd     = data_fd_;
+            poll_fds[0].events = POLLRDHUP | POLLIN;
+        }
+
+        int poll_res = poll(poll_fds, NELEM(poll_fds), 50);
+        if (poll_res < 0) {
+            ALOGE("Fatal error (%d,%d) while waiting on events",
+                 poll_res, errno);
+            goto bailout;
+        }
+
+        if (exitPending())
+            break;
+
+        if (poll_fds[0].revents) {
+            if (poll_fds[0].fd == listen_fd_) {
+                data_fd_ = accept(listen_fd_, NULL, NULL);
+
+                if (data_fd_ < 0) {
+                    ALOGW("Failed accept on socket %d with err %d",
+                         listen_fd_, errno);
+                } else {
+                    if (!setNonblocking(data_fd_))
+                        cleanupDataSocket();
+                    if (!setNodelay(data_fd_))
+                        cleanupDataSocket();
+                }
+            } else
+                if (poll_fds[0].fd == data_fd_) {
+                    if (poll_fds[0].revents & POLLRDHUP) {
+                        // Connection hung up; time to clean up.
+                        cleanupDataSocket();
+                    } else
+                        if (poll_fds[0].revents & POLLIN) {
+                            uint8_t cmd;
+                            if (read(data_fd_, &cmd, sizeof(cmd)) > 0) {
+                                switch(cmd) {
+                                    case 'r':
+                                    case 'R':
+                                        resetLogIDs();
+                                        break;
+                                }
+                            }
+                        }
+                }
+        }
+
+        struct local_time_debug_event events[kMaxEvents];
+        int amt = local_clock_->getDebugLog(events, kMaxEvents);
+
+        if (amt > 0) {
+            for (int i = 0; i < amt; i++) {
+                struct local_time_debug_event& e = events[i];
+
+                if (!kernel_logID_basis_known_) {
+                    kernel_logID_basis_ = e.local_timesync_event_id;
+                    kernel_logID_basis_known_ = true;
+                }
+
+                char buf[1024];
+                int64_t common_time;
+                status_t res = common_clock_->localToCommon(e.local_time,
+                                                            &common_time);
+                snprintf(buf, sizeof(buf), "E,%lld,%lld,%lld,%d\n",
+                         e.local_timesync_event_id - kernel_logID_basis_,
+                         e.local_time,
+                         common_time,
+                         (OK == res) ? 1 : 0);
+                buf[sizeof(buf) - 1] = 0;
+
+                if (data_fd_ >= 0)
+                    write(data_fd_, buf, strlen(buf));
+            }
+        }
+
+        { // scope for autolock pattern
+            Mutex::Autolock lock(&discipline_log_lock_);
+
+            while (discipline_log_.size() > 0) {
+                char buf[1024];
+                DisciplineEventRecord& e = *discipline_log_.begin();
+                snprintf(buf, sizeof(buf),
+                         "D,%lld,%lld,%lld,%lld,%lld,%lld,%d,%d\n",
+                         e.event_id,
+                         e.action_local_time,
+                         e.action_common_time,
+                         e.observed_local_time,
+                         e.observed_common_time,
+                         e.nominal_common_time,
+                         e.total_correction,
+                         e.rtt);
+                buf[sizeof(buf) - 1] = 0;
+
+                if (data_fd_ >= 0)
+                    write(data_fd_, buf, strlen(buf));
+
+                discipline_log_.erase(discipline_log_.begin());
+            }
+        }
+    }
+
+bailout:
+    cleanupDataSocket();
+    cleanupListenSocket();
+    return false;
+}
+
+}  // namespace android
diff --git a/services/common_time/diag_thread.h b/services/common_time/diag_thread.h
new file mode 100644
index 0000000..c630e0d
--- /dev/null
+++ b/services/common_time/diag_thread.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DIAG_THREAD_H__
+#define __DIAG_THREAD_H__
+
+#include <utils/List.h>
+#include <utils/threads.h>
+
+namespace android {
+
+class CommonClock;
+class LocalClock;
+
+class DiagThread : public Thread {
+  public:
+    DiagThread(CommonClock* common_clock, LocalClock* local_clock);
+    ~DiagThread();
+
+    status_t      startWorkThread();
+    void          stopWorkThread();
+    virtual bool  threadLoop();
+
+    void pushDisciplineEvent(int64_t observed_local_time,
+                             int64_t observed_common_time,
+                             int64_t nominal_common_time,
+                             int32_t total_correction,
+                             int32_t rtt);
+
+  private:
+    typedef struct {
+        int64_t event_id;
+        int64_t action_local_time;
+        int64_t action_common_time;
+        int64_t observed_local_time;
+        int64_t observed_common_time;
+        int64_t nominal_common_time;
+        int32_t total_correction;
+        int32_t rtt;
+    } DisciplineEventRecord;
+
+    bool            openListenSocket();
+    void            cleanupListenSocket();
+    void            cleanupDataSocket();
+    void            resetLogIDs();
+
+    CommonClock*    common_clock_;
+    LocalClock*     local_clock_;
+    int             listen_fd_;
+    int             data_fd_;
+
+    int64_t         kernel_logID_basis_;
+    bool            kernel_logID_basis_known_;
+
+    static const size_t         kMaxDisciplineLogSize = 16;
+    Mutex                       discipline_log_lock_;
+    List<DisciplineEventRecord> discipline_log_;
+    int64_t                     discipline_log_ID_;
+};
+
+}  // namespace android
+
+#endif  //__ DIAG_THREAD_H__
diff --git a/services/common_time/main.cpp b/services/common_time/main.cpp
new file mode 100644
index 0000000..49eb30a
--- /dev/null
+++ b/services/common_time/main.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * A service that exchanges time synchronization information between
+ * a master that defines a timeline and clients that follow the timeline.
+ */
+
+#define LOG_TAG "common_time"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+
+#include "common_time_server.h"
+
+int main(int argc, char *argv[]) {
+    using namespace android;
+
+    sp<CommonTimeServer> service = new CommonTimeServer();
+    if (service == NULL)
+        return 1;
+
+    ProcessState::self()->startThreadPool();
+    service->run("CommonTimeServer", ANDROID_PRIORITY_NORMAL);
+
+    IPCThreadState::self()->joinThreadPool();
+    return 0;
+}
+
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 86c6c8a..159800f 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -29,6 +29,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libcutils \
+    libandroidfw \
     libutils \
     libhardware \
     libhardware_legacy \
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index 296c95e..1b74aa6 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -36,9 +36,9 @@
 #include <errno.h>
 #include <assert.h>
 
-#include <ui/KeyLayoutMap.h>
-#include <ui/KeyCharacterMap.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/VirtualKeyMap.h>
 
 #include <string.h>
 #include <stdint.h>
diff --git a/services/input/EventHub.h b/services/input/EventHub.h
index 8a2afd3..4eb47c6 100644
--- a/services/input/EventHub.h
+++ b/services/input/EventHub.h
@@ -18,11 +18,11 @@
 #ifndef _RUNTIME_EVENT_HUB_H
 #define _RUNTIME_EVENT_HUB_H
 
-#include <ui/Input.h>
-#include <ui/Keyboard.h>
-#include <ui/KeyLayoutMap.h>
-#include <ui/KeyCharacterMap.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/Input.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/VirtualKeyMap.h>
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Log.h>
diff --git a/services/input/InputApplication.h b/services/input/InputApplication.h
index 67ae94b..c04a935 100644
--- a/services/input/InputApplication.h
+++ b/services/input/InputApplication.h
@@ -17,7 +17,7 @@
 #ifndef _UI_INPUT_APPLICATION_H
 #define _UI_INPUT_APPLICATION_H
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
diff --git a/services/input/InputDispatcher.cpp b/services/input/InputDispatcher.cpp
index e6e28df..149c0d3 100644
--- a/services/input/InputDispatcher.cpp
+++ b/services/input/InputDispatcher.cpp
@@ -45,7 +45,7 @@
 #include "InputDispatcher.h"
 
 #include <cutils/log.h>
-#include <ui/PowerManager.h>
+#include <androidfw/PowerManager.h>
 
 #include <stddef.h>
 #include <unistd.h>
diff --git a/services/input/InputDispatcher.h b/services/input/InputDispatcher.h
index 5c517f51..4b36480 100644
--- a/services/input/InputDispatcher.h
+++ b/services/input/InputDispatcher.h
@@ -17,8 +17,8 @@
 #ifndef _UI_INPUT_DISPATCHER_H
 #define _UI_INPUT_DISPATCHER_H
 
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
 #include <utils/KeyedVector.h>
 #include <utils/Vector.h>
 #include <utils/threads.h>
diff --git a/services/input/InputListener.h b/services/input/InputListener.h
index f920cd1..b1dc0b8 100644
--- a/services/input/InputListener.h
+++ b/services/input/InputListener.h
@@ -17,7 +17,7 @@
 #ifndef _UI_INPUT_LISTENER_H
 #define _UI_INPUT_LISTENER_H
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <utils/RefBase.h>
 #include <utils/Vector.h>
 
diff --git a/services/input/InputManager.h b/services/input/InputManager.h
index df4d299..29584c9 100644
--- a/services/input/InputManager.h
+++ b/services/input/InputManager.h
@@ -25,8 +25,8 @@
 #include "InputReader.h"
 #include "InputDispatcher.h"
 
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
 #include <utils/Errors.h>
 #include <utils/Vector.h>
 #include <utils/Timers.h>
diff --git a/services/input/InputReader.cpp b/services/input/InputReader.cpp
index 4be06e4..eccce29 100644
--- a/services/input/InputReader.cpp
+++ b/services/input/InputReader.cpp
@@ -39,8 +39,8 @@
 #include "InputReader.h"
 
 #include <cutils/log.h>
-#include <ui/Keyboard.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/Keyboard.h>
+#include <androidfw/VirtualKeyMap.h>
 
 #include <stddef.h>
 #include <stdlib.h>
diff --git a/services/input/InputReader.h b/services/input/InputReader.h
index ad89a22..9bbe49c 100644
--- a/services/input/InputReader.h
+++ b/services/input/InputReader.h
@@ -21,7 +21,7 @@
 #include "PointerController.h"
 #include "InputListener.h"
 
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <ui/DisplayInfo.h>
 #include <utils/KeyedVector.h>
 #include <utils/threads.h>
diff --git a/services/input/InputWindow.h b/services/input/InputWindow.h
index 38968f9..824a64b 100644
--- a/services/input/InputWindow.h
+++ b/services/input/InputWindow.h
@@ -17,8 +17,8 @@
 #ifndef _UI_INPUT_WINDOW_H
 #define _UI_INPUT_WINDOW_H
 
-#include <ui/Input.h>
-#include <ui/InputTransport.h>
+#include <androidfw/Input.h>
+#include <androidfw/InputTransport.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 #include <utils/String8.h>
diff --git a/services/input/PointerController.h b/services/input/PointerController.h
index 700ef72..39dbf6b 100644
--- a/services/input/PointerController.h
+++ b/services/input/PointerController.h
@@ -20,7 +20,7 @@
 #include "SpriteController.h"
 
 #include <ui/DisplayInfo.h>
-#include <ui/Input.h>
+#include <androidfw/Input.h>
 #include <utils/RefBase.h>
 #include <utils/Looper.h>
 #include <utils/String8.h>
diff --git a/services/input/tests/Android.mk b/services/input/tests/Android.mk
index 171db3c..8f8c34b 100644
--- a/services/input/tests/Android.mk
+++ b/services/input/tests/Android.mk
@@ -9,6 +9,7 @@
 
 shared_libraries := \
     libcutils \
+    libandroidfw \
     libutils \
     libhardware \
     libhardware_legacy \
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 41ede2e..9c408c4 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -463,7 +463,7 @@
                 Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DELETED);
                 intent.setComponent(p.info.provider);
                 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, id.appWidgetId);
-                mContext.sendBroadcast(intent);
+                mContext.sendBroadcast(intent, mUserId);
                 if (p.instances.size() == 0) {
                     // cancel the future updates
                     cancelBroadcasts(p);
@@ -471,7 +471,7 @@
                     // send the broacast saying that the provider is not in use any more
                     intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_DISABLED);
                     intent.setComponent(p.info.provider);
-                    mContext.sendBroadcast(intent);
+                    mContext.sendBroadcast(intent, mUserId);
                 }
             }
         }
@@ -515,8 +515,6 @@
                             + " safe mode: " + provider);
                 }
 
-                Binder.restoreCallingIdentity(ident);
-
                 id.provider = p;
                 p.instances.add(id);
                 int instancesSize = p.instances.size();
@@ -1066,7 +1064,7 @@
     void sendEnableIntentLocked(Provider p) {
         Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_ENABLED);
         intent.setComponent(p.info.provider);
-        mContext.sendBroadcast(intent);
+        mContext.sendBroadcast(intent, mUserId);
     }
 
     void sendUpdateIntentLocked(Provider p, int[] appWidgetIds) {
@@ -1074,7 +1072,7 @@
             Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
             intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
             intent.setComponent(p.info.provider);
-            mContext.sendBroadcast(intent);
+            mContext.sendBroadcast(intent, mUserId);
         }
     }
 
@@ -1477,12 +1475,11 @@
     }
 
     AtomicFile savedStateFile() {
-        int userId = UserId.getCallingUserId();
-        File dir = new File("/data/system/users/" + userId);
+        File dir = new File("/data/system/users/" + mUserId);
         File settingsFile = new File(dir, SETTINGS_FILENAME);
         if (!dir.exists()) {
             dir.mkdirs();
-            if (userId == 0) {
+            if (mUserId == 0) {
                 // Migrate old data
                 File oldFile = new File("/data/system/" + SETTINGS_FILENAME);
                 // Method doesn't throw an exception on failure. Ignore any errors
diff --git a/services/java/com/android/server/CommonTimeManagementService.java b/services/java/com/android/server/CommonTimeManagementService.java
new file mode 100644
index 0000000..9a25d2e
--- /dev/null
+++ b/services/java/com/android/server/CommonTimeManagementService.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.net.InetAddress;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.IConnectivityManager;
+import android.net.INetworkManagementEventObserver;
+import android.net.InterfaceConfiguration;
+import android.net.NetworkInfo;
+import android.os.Binder;
+import android.os.CommonTimeConfig;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.util.Log;
+
+/**
+ * @hide
+ * <p>CommonTimeManagementService manages the configuration of the native Common Time service,
+ * reconfiguring the native service as appropriate in response to changes in network configuration.
+ */
+class CommonTimeManagementService extends Binder {
+    /*
+     * Constants and globals.
+     */
+    private static final String TAG = CommonTimeManagementService.class.getSimpleName();
+    private static final int NATIVE_SERVICE_RECONNECT_TIMEOUT = 5000;
+    private static final String AUTO_DISABLE_PROP = "ro.common_time.auto_disable";
+    private static final String ALLOW_WIFI_PROP = "ro.common_time.allow_wifi";
+    private static final String SERVER_PRIO_PROP = "ro.common_time.server_prio";
+    private static final String NO_INTERFACE_TIMEOUT_PROP = "ro.common_time.no_iface_timeout";
+    private static final boolean AUTO_DISABLE;
+    private static final boolean ALLOW_WIFI;
+    private static final byte BASE_SERVER_PRIO;
+    private static final int NO_INTERFACE_TIMEOUT;
+    private static final InterfaceScoreRule[] IFACE_SCORE_RULES;
+
+    static {
+        int tmp;
+        AUTO_DISABLE         = (0 != SystemProperties.getInt(AUTO_DISABLE_PROP, 1));
+        ALLOW_WIFI           = (0 != SystemProperties.getInt(ALLOW_WIFI_PROP, 0));
+        tmp                  = SystemProperties.getInt(SERVER_PRIO_PROP, 1);
+        NO_INTERFACE_TIMEOUT = SystemProperties.getInt(NO_INTERFACE_TIMEOUT_PROP, 60000);
+
+        if (tmp < 1)
+            BASE_SERVER_PRIO = 1;
+        else
+        if (tmp > 30)
+            BASE_SERVER_PRIO = 30;
+        else
+            BASE_SERVER_PRIO = (byte)tmp;
+
+        if (ALLOW_WIFI) {
+            IFACE_SCORE_RULES = new InterfaceScoreRule[] {
+                new InterfaceScoreRule("wlan", (byte)1),
+                new InterfaceScoreRule("eth", (byte)2),
+            };
+        } else {
+            IFACE_SCORE_RULES = new InterfaceScoreRule[] {
+                new InterfaceScoreRule("eth", (byte)2),
+            };
+        }
+    };
+
+    /*
+     * Internal state
+     */
+    private final Context mContext;
+    private INetworkManagementService mNetMgr;
+    private CommonTimeConfig mCTConfig;
+    private String mCurIface;
+    private Handler mReconnectHandler = new Handler();
+    private Handler mNoInterfaceHandler = new Handler();
+    private Object mLock = new Object();
+    private boolean mDetectedAtStartup = false;
+    private byte mEffectivePrio = BASE_SERVER_PRIO;
+
+    /*
+     * Callback handler implementations.
+     */
+    private INetworkManagementEventObserver mIfaceObserver =
+        new INetworkManagementEventObserver.Stub() {
+
+        public void interfaceStatusChanged(String iface, boolean up) {
+            reevaluateServiceState();
+        }
+        public void interfaceLinkStateChanged(String iface, boolean up) {
+            reevaluateServiceState();
+        }
+        public void interfaceAdded(String iface) {
+            reevaluateServiceState();
+        }
+        public void interfaceRemoved(String iface) {
+            reevaluateServiceState();
+        }
+        public void limitReached(String limitName, String iface) { }
+    };
+
+    private BroadcastReceiver mConnectivityMangerObserver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            reevaluateServiceState();
+        }
+    };
+
+    private CommonTimeConfig.OnServerDiedListener mCTServerDiedListener =
+        new CommonTimeConfig.OnServerDiedListener() {
+            public void onServerDied() {
+                scheduleTimeConfigReconnect();
+            }
+        };
+
+    private Runnable mReconnectRunnable = new Runnable() {
+        public void run() { connectToTimeConfig(); }
+    };
+
+    private Runnable mNoInterfaceRunnable = new Runnable() {
+        public void run() { handleNoInterfaceTimeout(); }
+    };
+
+    /*
+     * Public interface (constructor, systemReady and dump)
+     */
+    public CommonTimeManagementService(Context context) {
+        mContext = context;
+    }
+
+    void systemReady() {
+        if (ServiceManager.checkService(CommonTimeConfig.SERVICE_NAME) == null) {
+            Log.i(TAG, "No common time service detected on this platform.  " +
+                       "Common time services will be unavailable.");
+            return;
+        }
+
+        mDetectedAtStartup = true;
+
+        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+        mNetMgr = INetworkManagementService.Stub.asInterface(b);
+
+        // Network manager is running along-side us, so we should never receiver a remote exception
+        // while trying to register this observer.
+        try {
+            mNetMgr.registerObserver(mIfaceObserver);
+        }
+        catch (RemoteException e) { }
+
+        // Register with the connectivity manager for connectivity changed intents.
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
+        mContext.registerReceiver(mConnectivityMangerObserver, filter);
+
+        // Connect to the common time config service and apply the initial configuration.
+        connectToTimeConfig();
+    }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println(String.format(
+                        "Permission Denial: can't dump CommonTimeManagement service from from " +
+                        "pid=%d, uid=%d", Binder.getCallingPid(), Binder.getCallingUid()));
+            return;
+        }
+
+        if (!mDetectedAtStartup) {
+            pw.println("Native Common Time service was not detected at startup.  " +
+                       "Service is unavailable");
+            return;
+        }
+
+        synchronized (mLock) {
+            pw.println("Current Common Time Management Service Config:");
+            pw.println(String.format("  Native service     : %s",
+                                     (null == mCTConfig) ? "reconnecting"
+                                                         : "alive"));
+            pw.println(String.format("  Bound interface    : %s",
+                                     (null == mCurIface ? "unbound" : mCurIface)));
+            pw.println(String.format("  Allow WiFi         : %s", ALLOW_WIFI ? "yes" : "no"));
+            pw.println(String.format("  Allow Auto Disable : %s", AUTO_DISABLE ? "yes" : "no"));
+            pw.println(String.format("  Server Priority    : %d", mEffectivePrio));
+            pw.println(String.format("  No iface timeout   : %d", NO_INTERFACE_TIMEOUT));
+        }
+    }
+
+    /*
+     * Inner helper classes
+     */
+    private static class InterfaceScoreRule {
+        public final String mPrefix;
+        public final byte mScore;
+        public InterfaceScoreRule(String prefix, byte score) {
+            mPrefix = prefix;
+            mScore = score;
+        }
+    };
+
+    /*
+     * Internal implementation
+     */
+    private void cleanupTimeConfig() {
+        mReconnectHandler.removeCallbacks(mReconnectRunnable);
+        mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
+        if (null != mCTConfig) {
+            mCTConfig.release();
+            mCTConfig = null;
+        }
+    }
+
+    private void connectToTimeConfig() {
+        // Get access to the common time service configuration interface.  If we catch a remote
+        // exception in the process (service crashed or no running for w/e reason), schedule an
+        // attempt to reconnect in the future.
+        cleanupTimeConfig();
+        try {
+            synchronized (mLock) {
+                mCTConfig = new CommonTimeConfig();
+                mCTConfig.setServerDiedListener(mCTServerDiedListener);
+                mCurIface = mCTConfig.getInterfaceBinding();
+                mCTConfig.setAutoDisable(AUTO_DISABLE);
+                mCTConfig.setMasterElectionPriority(mEffectivePrio);
+            }
+
+            if (NO_INTERFACE_TIMEOUT >= 0)
+                mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
+
+            reevaluateServiceState();
+        }
+        catch (RemoteException e) {
+            scheduleTimeConfigReconnect();
+        }
+    }
+
+    private void scheduleTimeConfigReconnect() {
+        cleanupTimeConfig();
+        Log.w(TAG, String.format("Native service died, will reconnect in %d mSec",
+                                 NATIVE_SERVICE_RECONNECT_TIMEOUT));
+        mReconnectHandler.postDelayed(mReconnectRunnable,
+                                      NATIVE_SERVICE_RECONNECT_TIMEOUT);
+    }
+
+    private void handleNoInterfaceTimeout() {
+        if (null != mCTConfig) {
+            Log.i(TAG, "Timeout waiting for interface to come up.  " +
+                       "Forcing networkless master mode.");
+            if (CommonTimeConfig.ERROR_DEAD_OBJECT == mCTConfig.forceNetworklessMasterMode())
+                scheduleTimeConfigReconnect();
+        }
+    }
+
+    private void reevaluateServiceState() {
+        String bindIface = null;
+        byte bestScore = -1;
+        try {
+            // Check to see if this interface is suitable to use for time synchronization.
+            //
+            // TODO : This selection algorithm needs to be enhanced for use with mobile devices.  In
+            // particular, the choice of whether to a wireless interface or not should not be an all
+            // or nothing thing controlled by properties.  It would probably be better if the
+            // platform had some concept of public wireless networks vs. home or friendly wireless
+            // networks (something a user would configure in settings or when a new interface is
+            // added).  Then this algorithm could pick only wireless interfaces which were flagged
+            // as friendly, and be dormant when on public wireless networks.
+            //
+            // Another issue which needs to be dealt with is the use of driver supplied interface
+            // name to determine the network type.  The fact that the wireless interface on a device
+            // is named "wlan0" is just a matter of convention; its not a 100% rule.  For example,
+            // there are devices out there where the wireless is name "tiwlan0", not "wlan0".  The
+            // internal network management interfaces in Android have all of the information needed
+            // to make a proper classification, there is just no way (currently) to fetch an
+            // interface's type (available from the ConnectionManager) as well as its address
+            // (available from either the java.net interfaces or from the NetworkManagment service).
+            // Both can enumerate interfaces, but that is no way to correlate their results (no
+            // common shared key; although using the interface name in the connection manager would
+            // be a good start).  Until this gets resolved, we resort to substring searching for
+            // tags like wlan and eth.
+            //
+            String ifaceList[] = mNetMgr.listInterfaces();
+            if (null != ifaceList) {
+                for (String iface : ifaceList) {
+
+                    byte thisScore = -1;
+                    for (InterfaceScoreRule r : IFACE_SCORE_RULES) {
+                        if (iface.contains(r.mPrefix)) {
+                            thisScore = r.mScore;
+                            break;
+                        }
+                    }
+
+                    if (thisScore <= bestScore)
+                        continue;
+
+                    InterfaceConfiguration config = mNetMgr.getInterfaceConfig(iface);
+                    if (null == config)
+                        continue;
+
+                    if (config.isActive()) {
+                        bindIface = iface;
+                        bestScore = thisScore;
+                    }
+                }
+            }
+        }
+        catch (RemoteException e) {
+            // Bad news; we should not be getting remote exceptions from the connectivity manager
+            // since it is running in SystemServer along side of us.  It probably does not matter
+            // what we do here, but go ahead and unbind the common time service in this case, just
+            // so we have some defined behavior.
+            bindIface = null;
+        }
+
+        boolean doRebind = true;
+        synchronized (mLock) {
+            if ((null != bindIface) && (null == mCurIface)) {
+                Log.e(TAG, String.format("Binding common time service to %s.", bindIface));
+                mCurIface = bindIface;
+            } else
+            if ((null == bindIface) && (null != mCurIface)) {
+                Log.e(TAG, "Unbinding common time service.");
+                mCurIface = null;
+            } else
+            if ((null != bindIface) && (null != mCurIface) && !bindIface.equals(mCurIface)) {
+                Log.e(TAG, String.format("Switching common time service binding from %s to %s.",
+                                         mCurIface, bindIface));
+                mCurIface = bindIface;
+            } else {
+                doRebind = false;
+            }
+        }
+
+        if (doRebind && (null != mCTConfig)) {
+            byte newPrio = (bestScore > 0)
+                         ? (byte)(bestScore * BASE_SERVER_PRIO)
+                         : BASE_SERVER_PRIO;
+            if (newPrio != mEffectivePrio) {
+                mEffectivePrio = newPrio;
+                mCTConfig.setMasterElectionPriority(mEffectivePrio);
+            }
+
+            int res = mCTConfig.setNetworkBinding(mCurIface);
+            if (res != CommonTimeConfig.SUCCESS)
+                scheduleTimeConfigReconnect();
+
+            else if (NO_INTERFACE_TIMEOUT >= 0) {
+                mNoInterfaceHandler.removeCallbacks(mNoInterfaceRunnable);
+                if (null == mCurIface)
+                    mNoInterfaceHandler.postDelayed(mNoInterfaceRunnable, NO_INTERFACE_TIMEOUT);
+            }
+        }
+    }
+}
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index e953355..7b4372f 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -583,6 +583,7 @@
         }
         
         nativeInit();
+        Power.powerInitNative();
         synchronized (mLocks) {
             updateNativePowerStateLocked();
             // We make sure to start out with the screen on due to user activity.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0dbc7c3..c9b5997 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -132,6 +132,7 @@
         RecognitionManagerService recognition = null;
         ThrottleService throttle = null;
         NetworkTimeUpdateService networkTimeUpdater = null;
+        CommonTimeManagementService commonTimeMgmtService = null;
 
         // Critical services...
         try {
@@ -575,6 +576,14 @@
             } catch (Throwable e) {
                 reportWtf("starting NetworkTimeUpdate service", e);
             }
+
+            try {
+                Slog.i(TAG, "CommonTimeManagementService");
+                commonTimeMgmtService = new CommonTimeManagementService(context);
+                ServiceManager.addService("commontime_management", commonTimeMgmtService);
+            } catch (Throwable e) {
+                reportWtf("starting CommonTimeManagementService service", e);
+            }
         }
 
         // Before things start rolling, be sure we have decided whether
@@ -653,6 +662,7 @@
         final LocationManagerService locationF = location;
         final CountryDetectorService countryDetectorF = countryDetector;
         final NetworkTimeUpdateService networkTimeUpdaterF = networkTimeUpdater;
+        final CommonTimeManagementService commonTimeMgmtServiceF = commonTimeMgmtService;
         final TextServicesManagerService textServiceManagerServiceF = tsms;
         final StatusBarManagerService statusBarF = statusBar;
 
@@ -752,6 +762,11 @@
                     reportWtf("making Network Time Service ready", e);
                 }
                 try {
+                    if (commonTimeMgmtServiceF != null) commonTimeMgmtServiceF.systemReady();
+                } catch (Throwable e) {
+                    reportWtf("making Common time management service ready", e);
+                }
+                try {
                     if (textServiceManagerServiceF != null) textServiceManagerServiceF.systemReady();
                 } catch (Throwable e) {
                     reportWtf("making Text Services Manager Service ready", e);
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 586a67e..455325a 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -86,8 +86,8 @@
 
     private static final String LOG_TAG = "AccessibilityManagerService";
 
-    private static final String FUNCTION_REGISTER_EVENT_LISTENER =
-        "registerEventListener";
+    private static final String FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE =
+        "registerUiTestAutomationService";
 
     private static int sIdCounter = 0;
 
@@ -95,10 +95,6 @@
 
     private static final int DO_SET_SERVICE_INFO = 10;
 
-    public static final int ACTIVE_WINDOW_ID = -1;
-
-    public static final long ROOT_NODE_ID = -1;
-
     private static int sNextWindowId;
 
     final HandlerCaller mCaller;
@@ -241,19 +237,9 @@
                 if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) {
                     synchronized (mLock) {
                         populateAccessibilityServiceListLocked();
-                        // get accessibility enabled setting on boot
-                        mIsAccessibilityEnabled = Settings.Secure.getInt(
-                                mContext.getContentResolver(),
-                                Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1;
-
-                        manageServicesLocked();
-
-                        // get touch exploration enabled setting on boot
-                        mIsTouchExplorationEnabled = Settings.Secure.getInt(
-                                mContext.getContentResolver(),
-                                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
+                        handleAccessibilityEnabledSettingChangedLocked();
+                        handleTouchExplorationEnabledSettingChangedLocked();
                         updateInputFilterLocked();
-
                         sendStateToClientsLocked();
                     }
                     
@@ -301,9 +287,10 @@
                 @Override
                 public void onChange(boolean selfChange) {
                     super.onChange(selfChange);
-
                     synchronized (mLock) {
                         handleAccessibilityEnabledSettingChangedLocked();
+                        updateInputFilterLocked();
+                        sendStateToClientsLocked();
                     }
                 }
             });
@@ -315,11 +302,8 @@
                     @Override
                     public void onChange(boolean selfChange) {
                         super.onChange(selfChange);
-
                         synchronized (mLock) {
-                            mIsTouchExplorationEnabled = Settings.Secure.getInt(
-                                    mContext.getContentResolver(),
-                                    Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
+                            handleTouchExplorationEnabledSettingChangedLocked();
                             updateInputFilterLocked();
                             sendStateToClientsLocked();
                         }
@@ -333,7 +317,6 @@
                 @Override
                 public void onChange(boolean selfChange) {
                     super.onChange(selfChange);
-
                     synchronized (mLock) {
                         manageServicesLocked();
                     }
@@ -475,7 +458,7 @@
     public void registerUiTestAutomationService(IEventListener listener,
             AccessibilityServiceInfo accessibilityServiceInfo) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
-                FUNCTION_REGISTER_EVENT_LISTENER);
+                FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
         ComponentName componentName = new ComponentName("foo.bar",
                 "AutomationAccessibilityService");
         synchronized (mLock) {
@@ -905,8 +888,15 @@
         } else {
             unbindAllServicesLocked();
         }
-        updateInputFilterLocked();
-        sendStateToClientsLocked();
+    }
+
+    /**
+     * Updates the state based on the touch exploration enabled setting.
+     */
+    private void handleTouchExplorationEnabledSettingChangedLocked() {
+        mIsTouchExplorationEnabled = Settings.Secure.getInt(
+                mContext.getContentResolver(),
+                Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1;
     }
 
     private class AccessibilityConnectionWrapper implements DeathRecipient {
@@ -1229,13 +1219,16 @@
 
         public void binderDied() {
             synchronized (mLock) {
-                unlinkToOwnDeath();
+                // The death recipient is unregistered in tryRemoveServiceLocked
                 tryRemoveServiceLocked(this);
                 // We no longer have an automation service, so restore
                 // the state based on values in the settings database.
                 if (mIsAutomation) {
                     mUiAutomationService = null;
                     handleAccessibilityEnabledSettingChangedLocked();
+                    handleTouchExplorationEnabledSettingChangedLocked();
+                    updateInputFilterLocked();
+                    sendStateToClientsLocked();
                 }
             }
         }
@@ -1256,7 +1249,7 @@
         }
 
         private int resolveAccessibilityWindowId(int accessibilityWindowId) {
-            if (accessibilityWindowId == ACTIVE_WINDOW_ID) {
+            if (accessibilityWindowId == AccessibilityNodeInfo.ACTIVE_WINDOW_ID) {
                 return mSecurityPolicy.mRetrievalAlowingWindowId;
             }
             return accessibilityWindowId;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 9d5caae..8a5e7fc 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -138,7 +138,6 @@
 import java.lang.IllegalStateException;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -2752,7 +2751,13 @@
         }
 
         // Just in case...
-        mMainStack.appDiedLocked(app);
+        if (mMainStack.mPausingActivity != null && mMainStack.mPausingActivity.app == app) {
+            if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " +mMainStack.mPausingActivity);
+            mMainStack.mPausingActivity = null;
+        }
+        if (mMainStack.mLastPausedActivity != null && mMainStack.mLastPausedActivity.app == app) {
+            mMainStack.mLastPausedActivity = null;
+        }
 
         // Remove this application's activities from active lists.
         mMainStack.removeHistoryRecordsForAppLocked(app);
@@ -5754,7 +5759,7 @@
                 ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                 ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
                 if (cpr == null) {
-                    cpr = new ContentProviderRecord(cpi, app.info, comp);
+                    cpr = new ContentProviderRecord(this, cpi, app.info, comp);
                     mProviderMap.putProviderByClass(comp, cpr);
                 }
                 if (DEBUG_MU)
@@ -5826,7 +5831,8 @@
         return msg;
     }
 
-    boolean incProviderCount(ProcessRecord r, ContentProviderRecord cpr) {
+    boolean incProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
+            IBinder externalProcessToken) {
         if (r != null) {
             Integer cnt = r.conProviders.get(cpr);
             if (DEBUG_PROVIDER) Slog.v(TAG,
@@ -5842,12 +5848,13 @@
                 r.conProviders.put(cpr, new Integer(cnt.intValue()+1));
             }
         } else {
-            cpr.externals++;
+            cpr.addExternalProcessHandleLocked(externalProcessToken);
         }
         return false;
     }
 
-    boolean decProviderCount(ProcessRecord r, ContentProviderRecord cpr) {
+    boolean decProviderCount(ProcessRecord r, final ContentProviderRecord cpr,
+            IBinder externalProcessToken) {
         if (r != null) {
             Integer cnt = r.conProviders.get(cpr);
             if (DEBUG_PROVIDER) Slog.v(TAG,
@@ -5863,13 +5870,13 @@
                 r.conProviders.put(cpr, new Integer(cnt.intValue()-1));
             }
         } else {
-            cpr.externals++;
+            cpr.removeExternalProcessHandleLocked(externalProcessToken);
         }
         return false;
     }
 
     private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
-            String name) {
+            String name, IBinder token) {
         ContentProviderRecord cpr;
         ProviderInfo cpi = null;
 
@@ -5913,7 +5920,7 @@
 
                 // In this case the provider instance already exists, so we can
                 // return it right away.
-                final boolean countChanged = incProviderCount(r, cpr);
+                final boolean countChanged = incProviderCount(r, cpr, token);
                 if (countChanged) {
                     if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                         // If this is a perceptible app accessing the provider,
@@ -5947,7 +5954,7 @@
                         Slog.i(TAG,
                                 "Existing provider " + cpr.name.flattenToShortString()
                                 + " is crashing; detaching " + r);
-                        boolean lastRef = decProviderCount(r, cpr);
+                        boolean lastRef = decProviderCount(r, cpr, token);
                         appDiedLocked(cpr.proc, cpr.proc.pid, cpr.proc.thread);
                         if (!lastRef) {
                             // This wasn't the last ref our process had on
@@ -6005,7 +6012,7 @@
                             return null;
                         }
                         ai = getAppInfoForUser(ai, Binder.getOrigCallingUser());
-                        cpr = new ContentProviderRecord(cpi, ai, comp);
+                        cpr = new ContentProviderRecord(this, cpi, ai, comp);
                     } catch (RemoteException ex) {
                         // pm is in same process, this will never happen.
                     }
@@ -6075,8 +6082,9 @@
                 if (firstClass) {
                     mProviderMap.putProviderByClass(comp, cpr);
                 }
+
                 mProviderMap.putProviderByName(name, cpr);
-                incProviderCount(r, cpr);
+                incProviderCount(r, cpr, token);
             }
         }
 
@@ -6116,12 +6124,17 @@
             throw new SecurityException(msg);
         }
 
-        ContentProviderHolder contentProvider = getContentProviderImpl(caller, name);
-        return contentProvider;
+        return getContentProviderImpl(caller, name, null);
     }
 
-    private ContentProviderHolder getContentProviderExternal(String name) {
-        return getContentProviderImpl(null, name);
+    public ContentProviderHolder getContentProviderExternal(String name, IBinder token) {
+        enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+            "Do not have permission in call getContentProviderExternal()");
+        return getContentProviderExternalUnchecked(name, token);
+    }
+
+    private ContentProviderHolder getContentProviderExternalUnchecked(String name,IBinder token) {
+        return getContentProviderImpl(null, name, token);
     }
 
     /**
@@ -6157,14 +6170,20 @@
                         + cpr.info.name + " in process " + r.processName);
                 return;
             } else {
-                if (decProviderCount(r, localCpr)) {
+                if (decProviderCount(r, localCpr, null)) {
                     updateOomAdjLocked();
                 }
             }
         }
     }
 
-    private void removeContentProviderExternal(String name) {
+    public void removeContentProviderExternal(String name, IBinder token) {
+        enforceCallingPermission(android.Manifest.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY,
+            "Do not have permission in call removeContentProviderExternal()");
+        removeContentProviderExternalUnchecked(name, token);
+    }
+
+    private void removeContentProviderExternalUnchecked(String name, IBinder token) {
         synchronized (this) {
             ContentProviderRecord cpr = mProviderMap.getProviderByName(name,
                     Binder.getOrigCallingUser());
@@ -6178,11 +6197,18 @@
             ComponentName comp = new ComponentName(cpr.info.packageName, cpr.info.name);
             ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp,
                     Binder.getOrigCallingUser());
-            localCpr.externals--;
-            if (localCpr.externals < 0) {
-                Slog.e(TAG, "Externals < 0 for content provider " + localCpr);
+            if (localCpr.hasExternalProcessHandles()) {
+                if (localCpr.removeExternalProcessHandleLocked(token)) {
+                    updateOomAdjLocked();
+                } else {
+                    Slog.e(TAG, "Attmpt to remove content provider " + localCpr
+                            + " with no external reference for token: "
+                            + token + ".");
+                }
+            } else {
+                Slog.e(TAG, "Attmpt to remove content provider: " + localCpr
+                        + " with no external references.");
             }
-            updateOomAdjLocked();
         }
     }
     
@@ -6286,7 +6312,7 @@
         ContentProviderHolder holder = null;
 
         try {
-            holder = getContentProviderExternal(name);
+            holder = getContentProviderExternalUnchecked(name, null);
             if (holder != null) {
                 return holder.provider.getType(uri);
             }
@@ -6295,7 +6321,7 @@
             return null;
         } finally {
             if (holder != null) {
-                removeContentProviderExternal(name);
+                removeContentProviderExternalUnchecked(name, null);
             }
             Binder.restoreCallingIdentity(ident);
         }
@@ -6400,7 +6426,7 @@
     public ParcelFileDescriptor openContentUri(Uri uri) throws RemoteException {
         enforceNotIsolatedCaller("openContentUri");
         String name = uri.getAuthority();
-        ContentProviderHolder cph = getContentProviderExternal(name);
+        ContentProviderHolder cph = getContentProviderExternalUnchecked(name, null);
         ParcelFileDescriptor pfd = null;
         if (cph != null) {
             // We record the binder invoker's uid in thread-local storage before
@@ -6422,7 +6448,7 @@
             }
 
             // We've got the fd now, so we're done with the provider.
-            removeContentProviderExternal(name);
+            removeContentProviderExternalUnchecked(name, null);
         } else {
             Slog.d(TAG, "Failed to get provider for authority '" + name + "'");
         }
@@ -6467,7 +6493,7 @@
                 mMainStack.stopIfSleepingLocked();
                 final long endTime = System.currentTimeMillis() + timeout;
                 while (mMainStack.mResumedActivity != null
-                        || mMainStack.mPausingActivities.size() > 0) {
+                        || mMainStack.mPausingActivity != null) {
                     long delay = endTime - System.currentTimeMillis();
                     if (delay <= 0) {
                         Slog.w(TAG, "Activity manager shutdown timed out");
@@ -8274,13 +8300,8 @@
         }
 
         pw.println(" ");
-        if (mMainStack.mPausingActivities.size() > 0) {
-            pw.println("  mPausingActivities: " + Arrays.toString(
-                    mMainStack.mPausingActivities.toArray()));
-        }
-        if (mMainStack.mInputPausedActivities.size() > 0) {
-            pw.println("  mInputPausedActivities: " + Arrays.toString(
-                    mMainStack.mInputPausedActivities.toArray()));
+        if (mMainStack.mPausingActivity != null) {
+            pw.println("  mPausingActivity: " + mMainStack.mPausingActivity);
         }
         pw.println("  mResumedActivity: " + mMainStack.mResumedActivity);
         pw.println("  mFocusedActivity: " + mFocusedActivity);
@@ -10253,7 +10274,7 @@
             for (int i=0; i<NL; i++) {
                 ContentProviderRecord cpr = (ContentProviderRecord)
                         mLaunchingProviders.get(i);
-                if (cpr.clients.size() <= 0 && cpr.externals <= 0) {
+                if (cpr.clients.size() <= 0 && !cpr.hasExternalProcessHandles()) {
                     synchronized (cpr) {
                         cpr.launchingApp = null;
                         cpr.notifyAll();
@@ -13455,7 +13476,7 @@
                 // If the provider has external (non-framework) process
                 // dependencies, ensure that its adjustment is at least
                 // FOREGROUND_APP_ADJ.
-                if (cpr.externals != 0) {
+                if (cpr.hasExternalProcessHandles()) {
                     if (adj > ProcessList.FOREGROUND_APP_ADJ) {
                         adj = ProcessList.FOREGROUND_APP_ADJ;
                         schedGroup = Process.THREAD_GROUP_DEFAULT;
@@ -13855,13 +13876,7 @@
     private final ActivityRecord resumedAppLocked() {
         ActivityRecord resumedActivity = mMainStack.mResumedActivity;
         if (resumedActivity == null || resumedActivity.app == null) {
-            for (int i=mMainStack.mPausingActivities.size()-1; i>=0; i--) {
-                ActivityRecord r = mMainStack.mPausingActivities.get(i);
-                if (r.app != null) {
-                    resumedActivity = r;
-                    break;
-                }
-            }
+            resumedActivity = mMainStack.mPausingActivity;
             if (resumedActivity == null || resumedActivity.app == null) {
                 resumedActivity = mMainStack.topRunningActivityLocked(null);
             }
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index 977ee84..cdab6c6 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -602,7 +602,6 @@
     
     public void windowsDrawn() {
         synchronized(service) {
-            stack.reportActivityDrawnLocked(this);
             if (launchTime != 0) {
                 final long curTime = SystemClock.uptimeMillis();
                 final long thisTime = curTime - launchTime;
@@ -691,9 +690,7 @@
             // Hmmm, who might we be waiting for?
             r = stack.mResumedActivity;
             if (r == null) {
-                if (stack.mPausingActivities.size() > 0) {
-                    r = stack.mPausingActivities.get(stack.mPausingActivities.size()-1);
-                }
+                r = stack.mPausingActivity;
             }
             // Both of those null?  Fall back to 'this' again
             if (r == null) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index e8c8275..7b8bc26 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -227,13 +227,7 @@
      * When we are in the process of pausing an activity, before starting the
      * next one, this variable holds the activity that is currently being paused.
      */
-    final ArrayList<ActivityRecord> mPausingActivities = new ArrayList<ActivityRecord>();
-
-    /**
-     * These activities currently have their input paused, as they want for
-     * the next top activity to have its windows visible.
-     */
-    final ArrayList<ActivityRecord> mInputPausedActivities = new ArrayList<ActivityRecord>();
+    ActivityRecord mPausingActivity = null;
 
     /**
      * This is the last activity that we put into the paused state.  This is
@@ -813,9 +807,9 @@
                 startPausingLocked(false, true);
                 return;
             }
-            if (mPausingActivities.size() > 0) {
+            if (mPausingActivity != null) {
                 // Still waiting for something to pause; can't sleep yet.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivities);
+                if (DEBUG_PAUSE) Slog.v(TAG, "Sleep still waiting to pause " + mPausingActivity);
                 return;
             }
 
@@ -878,6 +872,11 @@
     }
 
     private final void startPausingLocked(boolean userLeaving, boolean uiSleeping) {
+        if (mPausingActivity != null) {
+            RuntimeException e = new RuntimeException();
+            Slog.e(TAG, "Trying to pause when pause is already pending for "
+                  + mPausingActivity, e);
+        }
         ActivityRecord prev = mResumedActivity;
         if (prev == null) {
             RuntimeException e = new RuntimeException();
@@ -885,25 +884,19 @@
             resumeTopActivityLocked(null);
             return;
         }
-        if (mPausingActivities.contains(prev)) {
-            RuntimeException e = new RuntimeException();
-            Slog.e(TAG, "Trying to pause when pause when already pausing " + prev, e);
-        }
         if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSING: " + prev);
         else if (DEBUG_PAUSE) Slog.v(TAG, "Start pausing: " + prev);
         mResumedActivity = null;
-        mPausingActivities.add(prev);
+        mPausingActivity = prev;
         mLastPausedActivity = prev;
         prev.state = ActivityState.PAUSING;
         prev.task.touchActiveTime();
         prev.updateThumbnail(screenshotActivities(prev), null);
 
         mService.updateCpuStats();
-        ActivityRecord pausing;
         
         if (prev.app != null && prev.app.thread != null) {
             if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending pause: " + prev);
-            pausing = prev;
             try {
                 EventLog.writeEvent(EventLogTags.AM_PAUSE_ACTIVITY,
                         System.identityHashCode(prev),
@@ -916,14 +909,12 @@
             } catch (Exception e) {
                 // Ignore exception, if process died other code will cleanup.
                 Slog.w(TAG, "Exception thrown during pause", e);
-                mPausingActivities.remove(prev);
+                mPausingActivity = null;
                 mLastPausedActivity = null;
-                pausing = null;
             }
         } else {
-            mPausingActivities.remove(prev);
+            mPausingActivity = null;
             mLastPausedActivity = null;
-            pausing = null;
         }
 
         // If we are not going to sleep, we want to ensure the device is
@@ -937,28 +928,18 @@
             }
         }
 
-        if (pausing != null) {
+
+        if (mPausingActivity != null) {
             // Have the window manager pause its key dispatching until the new
             // activity has started.  If we're pausing the activity just because
             // the screen is being turned off and the UI is sleeping, don't interrupt
             // key dispatch; the same activity will pick it up again on wakeup.
             if (!uiSleeping) {
-                pausing.pauseKeyDispatchingLocked();
-                mInputPausedActivities.add(prev);
+                prev.pauseKeyDispatchingLocked();
             } else {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Key dispatch not paused for screen off");
             }
 
-            if (pausing.configDestroy) {
-                // The previous is being paused because the configuration
-                // is changing, which means it is actually stopping...
-                // To juggle the fact that we are also starting a new
-                // instance right now, we need to first completely stop
-                // the current instance before starting the new one.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Destroying at pause: " + prev);
-                destroyActivityLocked(pausing, true, false, "pause-config");
-            }
-
             // Schedule a pause timeout in case the app doesn't respond.
             // We don't give it much time because this directly impacts the
             // responsiveness seen by the user.
@@ -970,10 +951,7 @@
             // This activity failed to schedule the
             // pause, so just treat it as being paused now.
             if (DEBUG_PAUSE) Slog.v(TAG, "Activity not running, resuming next.");
-        }
-
-        if (!mService.isSleeping()) {
-            resumeTopActivityLocked(pausing);
+            resumeTopActivityLocked(null);
         }
     }
     
@@ -988,17 +966,16 @@
             if (index >= 0) {
                 r = mHistory.get(index);
                 mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-                if (mPausingActivities.contains(r)) {
+                if (mPausingActivity == r) {
                     if (DEBUG_STATES) Slog.v(TAG, "Moving to PAUSED: " + r
                             + (timeout ? " (due to timeout)" : " (pause complete)"));
                     r.state = ActivityState.PAUSED;
-                    completePauseLocked(r);
+                    completePauseLocked();
                 } else {
-                    ActivityRecord old = mPausingActivities.size() > 0
-                            ? mPausingActivities.get(0) : null;
                     EventLog.writeEvent(EventLogTags.AM_FAILED_TO_PAUSE,
                             System.identityHashCode(r), r.shortComponentName, 
-                            old != null ? old.shortComponentName : "(none)");
+                            mPausingActivity != null
+                                ? mPausingActivity.shortComponentName : "(none)");
                 }
             }
         }
@@ -1024,14 +1001,8 @@
                 ProcessRecord fgApp = null;
                 if (mResumedActivity != null) {
                     fgApp = mResumedActivity.app;
-                } else {
-                    for (int i=mPausingActivities.size()-1; i>=0; i--) {
-                        ActivityRecord pausing = mPausingActivities.get(i);
-                        if (pausing.app == r.app) {
-                            fgApp = pausing.app;
-                            break;
-                        }
-                    }
+                } else if (mPausingActivity != null) {
+                    fgApp = mPausingActivity.app;
                 }
                 if (r.app != null && fgApp != null && r.app != fgApp
                         && r.lastVisibleTime > mService.mPreviousProcessVisibleTime
@@ -1043,49 +1014,58 @@
         }
     }
 
-    private final void completePauseLocked(ActivityRecord prev) {
+    private final void completePauseLocked() {
+        ActivityRecord prev = mPausingActivity;
         if (DEBUG_PAUSE) Slog.v(TAG, "Complete pause: " + prev);
         
-        if (prev.finishing) {
-            if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
-            prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
-        } else if (prev.app != null) {
-            if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
-            if (prev.waitingVisible) {
-                prev.waitingVisible = false;
-                mWaitingVisibleActivities.remove(prev);
-                if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
-                        TAG, "Complete pause, no longer waiting: " + prev);
-            }
-            if (prev.configDestroy) {
-                // The previous is being paused because the configuration
-                // is changing, which means it is actually stopping...
-                // To juggle the fact that we are also starting a new
-                // instance right now, we need to first completely stop
-                // the current instance before starting the new one.
-                if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
-                destroyActivityLocked(prev, true, false, "pause-config");
-            } else {
-                mStoppingActivities.add(prev);
-                if (mStoppingActivities.size() > 3) {
-                    // If we already have a few activities waiting to stop,
-                    // then give up on things going idle and start clearing
-                    // them out.
-                    if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
-                    scheduleIdleLocked();
-                } else {
-                    checkReadyForSleepLocked();
+        if (prev != null) {
+            if (prev.finishing) {
+                if (DEBUG_PAUSE) Slog.v(TAG, "Executing finish of activity: " + prev);
+                prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE);
+            } else if (prev.app != null) {
+                if (DEBUG_PAUSE) Slog.v(TAG, "Enqueueing pending stop: " + prev);
+                if (prev.waitingVisible) {
+                    prev.waitingVisible = false;
+                    mWaitingVisibleActivities.remove(prev);
+                    if (DEBUG_SWITCH || DEBUG_PAUSE) Slog.v(
+                            TAG, "Complete pause, no longer waiting: " + prev);
                 }
+                if (prev.configDestroy) {
+                    // The previous is being paused because the configuration
+                    // is changing, which means it is actually stopping...
+                    // To juggle the fact that we are also starting a new
+                    // instance right now, we need to first completely stop
+                    // the current instance before starting the new one.
+                    if (DEBUG_PAUSE) Slog.v(TAG, "Destroying after pause: " + prev);
+                    destroyActivityLocked(prev, true, false, "pause-config");
+                } else {
+                    mStoppingActivities.add(prev);
+                    if (mStoppingActivities.size() > 3) {
+                        // If we already have a few activities waiting to stop,
+                        // then give up on things going idle and start clearing
+                        // them out.
+                        if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
+                        scheduleIdleLocked();
+                    } else {
+                        checkReadyForSleepLocked();
+                    }
+                }
+            } else {
+                if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
+                prev = null;
             }
-        } else {
-            if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
-            prev = null;
+            mPausingActivity = null;
         }
-        mPausingActivities.remove(prev);
 
-        if (mService.isSleeping()) {
+        if (!mService.isSleeping()) {
+            resumeTopActivityLocked(prev);
+        } else {
             checkReadyForSleepLocked();
         }
+        
+        if (prev != null) {
+            prev.resumeKeyDispatchingLocked();
+        }
 
         if (prev.app != null && prev.cpuTimeAtResume > 0
                 && mService.mBatteryStatsService.isOnBattery()) {
@@ -1142,9 +1122,7 @@
         if (mMainStack) {
             mService.setFocusedActivityLocked(next);
         }
-        if (mInputPausedActivities.remove(next)) {
-            next.resumeKeyDispatchingLocked();
-        }
+        next.resumeKeyDispatchingLocked();
         ensureActivitiesVisibleLocked(null, 0);
         mService.mWindowManager.executeAppTransition();
         mNoAnimActivities.clear();
@@ -1374,6 +1352,13 @@
 
         if (DEBUG_SWITCH) Slog.v(TAG, "Resuming " + next);
 
+        // If we are currently pausing an activity, then don't do anything
+        // until that is done.
+        if (mPausingActivity != null) {
+            if (DEBUG_SWITCH) Slog.v(TAG, "Skip resume: pausing=" + mPausingActivity);
+            return false;
+        }
+
         // Okay we are now going to start a switch, to 'next'.  We may first
         // have to pause the current activity, but this is an important point
         // where we have decided to go to 'next' so keep track of that.
@@ -2455,7 +2440,7 @@
         
         err = startActivityUncheckedLocked(r, sourceRecord,
                 grantedUriPermissions, grantedMode, onlyIfNeeded, true);
-        if (mDismissKeyguardOnNextActivity && mPausingActivities.size() == 0) {
+        if (mDismissKeyguardOnNextActivity && mPausingActivity == null) {
             // Someone asked to have the keyguard dismissed on the next
             // activity start, but we are not actually doing an activity
             // switch...  just dismiss the keyguard now, because we
@@ -3126,18 +3111,7 @@
         }
         mService.notifyAll();
     }
-
-    void reportActivityDrawnLocked(ActivityRecord r) {
-        if (mResumedActivity == r) {
-            // Once the resumed activity has been drawn, we can stop
-            // pausing input on all other activities.
-            for (int i=mInputPausedActivities.size()-1; i>=0; i--) {
-                mInputPausedActivities.get(i).resumeKeyDispatchingLocked();
-            }
-            mInputPausedActivities.clear();
-        }
-    }
-
+    
     void reportActivityVisibleLocked(ActivityRecord r) {
         for (int i=mWaitingActivityVisible.size()-1; i>=0; i--) {
             WaitResult w = mWaitingActivityVisible.get(i);
@@ -3196,9 +3170,7 @@
                     mService.setFocusedActivityLocked(topRunningActivityLocked(null));
                 }
             }
-            if (mInputPausedActivities.remove(r)) {
-                r.resumeKeyDispatchingLocked();
-            }
+            r.resumeKeyDispatchingLocked();
             try {
                 r.stopped = false;
                 if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPING: " + r
@@ -3524,7 +3496,7 @@
             // Tell window manager to prepare for this one to be removed.
             mService.mWindowManager.setAppVisibility(r.appToken, false);
                 
-            if (!mPausingActivities.contains(r)) {
+            if (mPausingActivity == null) {
                 if (DEBUG_PAUSE) Slog.v(TAG, "Finish needs to pause: " + r);
                 if (DEBUG_USER_LEAVING) Slog.v(TAG, "finish() => pause with userLeaving=false");
                 startPausingLocked(false, false);
@@ -3608,20 +3580,6 @@
         return r;
     }
 
-    final void appDiedLocked(ProcessRecord app) {
-        for (int i=mPausingActivities.size()-1; i>=0; i--) {
-            ActivityRecord r = mPausingActivities.get(i);
-            if (r.app == app) {
-                if (DEBUG_PAUSE) Slog.v(TAG, "App died while pausing: " + r);
-                mPausingActivities.remove(i);
-                mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
-            }
-        }
-        if (mLastPausedActivity != null && mLastPausedActivity.app == app) {
-            mLastPausedActivity = null;
-        }
-    }
-
     /**
      * Perform the common clean-up of an activity record.  This is called both
      * as part of destroyActivityLocked() (when destroying the client-side
diff --git a/services/java/com/android/server/am/ContentProviderRecord.java b/services/java/com/android/server/am/ContentProviderRecord.java
index 3835553..f338cfc 100644
--- a/services/java/com/android/server/am/ContentProviderRecord.java
+++ b/services/java/com/android/server/am/ContentProviderRecord.java
@@ -20,24 +20,35 @@
 import android.content.ComponentName;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ProviderInfo;
+import android.os.IBinder;
+import android.os.IBinder.DeathRecipient;
 import android.os.Process;
+import android.os.RemoteException;
+import android.util.Slog;
 
 import java.io.PrintWriter;
+import java.util.HashMap;
 import java.util.HashSet;
 
 class ContentProviderRecord extends ContentProviderHolder {
     // All attached clients
     final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
+    // Handles for non-framework processes supported by this provider
+    HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
+    // Count for external process for which we have no handles.
+    int externalProcessNoHandleCount;
+    final ActivityManagerService service;
     final int uid;
     final ApplicationInfo appInfo;
     final ComponentName name;
-    int externals;     // number of non-framework processes supported by this provider
     ProcessRecord proc; // if non-null, hosting process.
     ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
     String stringName;
-    
-    public ContentProviderRecord(ProviderInfo _info, ApplicationInfo ai, ComponentName _name) {
+
+    public ContentProviderRecord(ActivityManagerService _service, ProviderInfo _info,
+            ApplicationInfo ai, ComponentName _name) {
         super(_info);
+        service = _service;
         uid = ai.uid;
         appInfo = ai;
         name = _name;
@@ -50,6 +61,7 @@
         appInfo = cpr.appInfo;
         name = cpr.name;
         noReleaseNeeded = cpr.noReleaseNeeded;
+        service = cpr.service;
     }
 
     public boolean canRunHere(ProcessRecord app) {
@@ -57,6 +69,57 @@
                 && (uid == Process.SYSTEM_UID || uid == app.info.uid);
     }
 
+    public void addExternalProcessHandleLocked(IBinder token) {
+        if (token == null) {
+            externalProcessNoHandleCount++;
+        } else {
+            if (externalProcessTokenToHandle == null) {
+                externalProcessTokenToHandle = new HashMap<IBinder, ExternalProcessHandle>();
+            }
+            ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
+            if (handle == null) {
+                handle = new ExternalProcessHandle(token);
+                externalProcessTokenToHandle.put(token, handle);
+            }
+            handle.mAcquisitionCount++;
+        }
+    }
+
+    public boolean removeExternalProcessHandleLocked(IBinder token) {
+        if (hasExternalProcessHandles()) {
+            boolean hasHandle = false;
+            if (externalProcessTokenToHandle != null) {
+                ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
+                if (handle != null) {
+                    hasHandle = true;
+                    handle.mAcquisitionCount--;
+                    if (handle.mAcquisitionCount == 0) {
+                        removeExternalProcessHandleInternalLocked(token);
+                        return true;
+                    }
+                }
+            }
+            if (!hasHandle) {
+                externalProcessNoHandleCount--;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void removeExternalProcessHandleInternalLocked(IBinder token) {
+        ExternalProcessHandle handle = externalProcessTokenToHandle.get(token);
+        handle.unlinkFromOwnDeathLocked();
+        externalProcessTokenToHandle.remove(token);
+        if (externalProcessTokenToHandle.size() == 0) {
+            externalProcessTokenToHandle = null;
+        }
+    }
+
+    public boolean hasExternalProcessHandles() {
+        return (externalProcessTokenToHandle != null || externalProcessNoHandleCount > 0);
+    }
+
     void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("package=");
                 pw.print(info.applicationInfo.packageName);
@@ -73,8 +136,9 @@
                     pw.print("multiprocess="); pw.print(info.multiprocess);
                     pw.print(" initOrder="); pw.println(info.initOrder);
         }
-        if (externals != 0) {
-            pw.print(prefix); pw.print("externals="); pw.println(externals);
+        if (hasExternalProcessHandles()) {
+            pw.print(prefix); pw.print("externals=");
+            pw.println(externalProcessTokenToHandle.size());
         }
         if (clients.size() > 0) {
             pw.print(prefix); pw.println("Clients:");
@@ -84,6 +148,7 @@
         }
     }
 
+    @Override
     public String toString() {
         if (stringName != null) {
             return stringName;
@@ -96,4 +161,35 @@
         sb.append('}');
         return stringName = sb.toString();
     }
+
+    // This class represents a handle from an external process to a provider.
+    private class ExternalProcessHandle implements DeathRecipient {
+        private static final String LOG_TAG = "ExternalProcessHanldle";
+
+        private final IBinder mToken;
+        private int mAcquisitionCount;
+
+        public ExternalProcessHandle(IBinder token) {
+            mToken = token;
+            try {
+                token.linkToDeath(this, 0);
+            } catch (RemoteException re) {
+                Slog.e(LOG_TAG, "Couldn't register for death for token: " + mToken, re);
+            }
+        }
+
+        public void unlinkFromOwnDeathLocked() {
+            mToken.unlinkToDeath(this, 0);
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (service) {
+                if (hasExternalProcessHandles() &&
+                        externalProcessTokenToHandle.get(mToken) != null) {
+                    removeExternalProcessHandleInternalLocked(mToken);
+                }                        
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 54a2103..dafc613 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -6380,7 +6380,7 @@
                 INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
-        return reportInjectionResult(result);
+        return reportInjectionResult(result, pid);
     }
 
     /**
@@ -6410,7 +6410,7 @@
                 INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
-        return reportInjectionResult(result);
+        return reportInjectionResult(result, pid);
     }
 
     /**
@@ -6440,7 +6440,7 @@
                 INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
-        return reportInjectionResult(result);
+        return reportInjectionResult(result, pid);
     }
     
     /**
@@ -6461,24 +6461,23 @@
                 INJECTION_TIMEOUT_MILLIS);
         
         Binder.restoreCallingIdentity(ident);
-        return reportInjectionResult(result);
+        return reportInjectionResult(result, pid);
     }
     
-    private boolean reportInjectionResult(int result) {
+    private boolean reportInjectionResult(int result, int pid) {
         switch (result) {
             case InputManager.INPUT_EVENT_INJECTION_PERMISSION_DENIED:
-                Slog.w(TAG, "Input event injection permission denied.");
+                Slog.w(TAG, "Input event injection from pid " + pid + " permission denied.");
                 throw new SecurityException(
                         "Injecting to another application requires INJECT_EVENTS permission");
             case InputManager.INPUT_EVENT_INJECTION_SUCCEEDED:
-                //Slog.v(TAG, "Input event injection succeeded.");
                 return true;
             case InputManager.INPUT_EVENT_INJECTION_TIMED_OUT:
-                Slog.w(TAG, "Input event injection timed out.");
+                Slog.w(TAG, "Input event injection from pid " + pid + " timed out.");
                 return false;
             case InputManager.INPUT_EVENT_INJECTION_FAILED:
             default:
-                Slog.w(TAG, "Input event injection failed.");
+                Slog.w(TAG, "Input event injection from pid " + pid + " failed.");
                 return false;
         }
     }
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index c63b84d..c02dd36 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -26,6 +26,7 @@
 
 LOCAL_SHARED_LIBRARIES := \
     libandroid_runtime \
+    libandroidfw \
     libcutils \
     libhardware \
     libhardware_legacy \
diff --git a/services/jni/com_android_server_PowerManagerService.h b/services/jni/com_android_server_PowerManagerService.h
index af10711..cc3b5ef5 100644
--- a/services/jni/com_android_server_PowerManagerService.h
+++ b/services/jni/com_android_server_PowerManagerService.h
@@ -20,7 +20,7 @@
 #include "JNIHelp.h"
 #include "jni.h"
 
-#include <ui/PowerManager.h>
+#include <androidfw/PowerManager.h>
 
 namespace android {
 
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index c127fa6..c7cf46e 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -70,6 +70,8 @@
     glBindTexture(GL_TEXTURE_2D, mTextureName);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     mTexCoords[0] = 0;         mTexCoords[1] = v;
     mTexCoords[2] = 0;         mTexCoords[3] = 0;
     mTexCoords[4] = u;         mTexCoords[5] = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 40717f4..9e3f548 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1922,6 +1922,8 @@
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glVertexPointer(2, GL_FLOAT, 0, vtx);
@@ -2094,6 +2096,8 @@
     glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glVertexPointer(2, GL_FLOAT, 0, vtx);
diff --git a/services/surfaceflinger/tests/resize/resize.cpp b/services/surfaceflinger/tests/resize/resize.cpp
index 56b2a8f..7f3f064 100644
--- a/services/surfaceflinger/tests/resize/resize.cpp
+++ b/services/surfaceflinger/tests/resize/resize.cpp
@@ -39,7 +39,7 @@
     // create a client to surfaceflinger
     sp<SurfaceComposerClient> client = new SurfaceComposerClient();
     
-    sp<Surface> surface = client->createSurface(getpid(), 0, 160, 240, 
+    sp<Surface> surface = client->createSurface(0, 160, 240,
             PIXEL_FORMAT_RGB_565);
 
 
diff --git a/services/surfaceflinger/tests/surface/surface.cpp b/services/surfaceflinger/tests/surface/surface.cpp
index 8e1c3fe..9c15f9b 100644
--- a/services/surfaceflinger/tests/surface/surface.cpp
+++ b/services/surfaceflinger/tests/surface/surface.cpp
@@ -38,7 +38,7 @@
     sp<SurfaceComposerClient> client = new SurfaceComposerClient();
     
     sp<SurfaceControl> surfaceControl = client->createSurface(
-            getpid(), 0, 160, 240, PIXEL_FORMAT_RGB_565);
+            0, 160, 240, PIXEL_FORMAT_RGB_565);
     SurfaceComposerClient::openGlobalTransaction();
     surfaceControl->setLayer(100000);
     SurfaceComposerClient::closeGlobalTransaction();
diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java
index 674c0b7..5fab2bb 100644
--- a/test-runner/src/android/test/mock/MockContext.java
+++ b/test-runner/src/android/test/mock/MockContext.java
@@ -267,6 +267,12 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public void sendBroadcast(Intent intent, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void sendBroadcast(Intent intent, String receiverPermission) {
         throw new UnsupportedOperationException();
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 3904c21..ed78daa3 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -568,6 +568,15 @@
         </activity>
 
         <activity
+                android:name="PathsCacheActivity"
+                android:label="_PathsCache">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="PointsActivity"
                 android:label="_Points">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
new file mode 100644
index 0000000..b8ad823
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/PathsCacheActivity.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class PathsCacheActivity extends Activity {
+    private Path mPath;
+
+    private final Random mRandom = new Random();
+    private final ArrayList<Path> mPathList = new ArrayList<Path>();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        mPath = makePath();
+
+        final PathsView view = new PathsView(this);
+        setContentView(view);
+    }
+
+    private Path makePath() {
+        Path path = new Path();
+        buildPath(path);
+        return path;
+    }
+
+    private void buildPath(Path path) {
+        path.moveTo(0.0f, 0.0f);
+        path.cubicTo(0.0f, 0.0f, 100.0f, 150.0f, 100.0f, 200.0f);
+        path.cubicTo(100.0f, 200.0f, 50.0f, 300.0f, -80.0f, 200.0f);
+        path.cubicTo(-80.0f, 200.0f, 100.0f, 200.0f, 200.0f, 0.0f);
+    }
+
+    public class PathsView extends View {
+        private final Paint mMediumPaint;
+
+        public PathsView(Context c) {
+            super(c);
+
+            mMediumPaint = new Paint();
+            mMediumPaint.setAntiAlias(true);
+            mMediumPaint.setColor(0xe00000ff);
+            mMediumPaint.setStrokeWidth(10.0f);
+            mMediumPaint.setStyle(Paint.Style.STROKE);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            
+            Log.d("OpenGLRenderer", "Start frame");
+
+            canvas.drawARGB(255, 255, 255, 255);
+
+            canvas.save();
+            canvas.translate(550.0f, 60.0f);
+            canvas.drawPath(mPath, mMediumPaint);
+
+            mPath.reset();
+            buildPath(mPath);
+
+            canvas.translate(30.0f, 30.0f);
+            canvas.drawPath(mPath, mMediumPaint);
+            canvas.drawPath(mPath, mMediumPaint);
+
+            canvas.restore();
+
+//            Path path = makePath();
+//            int r = mRandom.nextInt(10);
+//            if (r == 5 || r == 3) {
+//                mPathList.add(path);
+//            } else if (r == 9) {
+//                mPathList.clear();
+//            }
+//
+//            canvas.save();
+//            canvas.translate(550.0f + mRandom.nextInt(50), 60.0f + mRandom.nextInt(50));
+//            canvas.drawPath(path, mMediumPaint);
+//            canvas.restore();
+//            
+            invalidate();
+        }
+    }
+}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
index c8cc3ac..c8e25feb 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java
@@ -48,6 +48,11 @@
             return this;
         }
 
+        public Builder setShader(String code) {
+            mBuilder.setShader(code);
+            return this;
+        }
+
         public Builder setObjectConst(Type type) {
             mShader.mPerObjConstants = type;
             return this;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
index 9f7ab41..3476e35 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java
@@ -196,6 +196,9 @@
     }
 
     void updateFieldItem(RenderScriptGL rs) {
+        if (mRenderState == null) {
+            mRenderState = SceneManager.getDefaultState();
+        }
         updateVertexConstants(rs);
         updateFragmentConstants(rs);
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
index 8c09860..e840346 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java
@@ -75,6 +75,9 @@
     }
 
     public void appendTransform(Transform t) {
+        if (t == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mRootTransforms.appendChild(t);
     }
 
@@ -88,6 +91,9 @@
     }
 
     public void appendRenderPass(RenderPass p) {
+        if (p == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mRenderPasses.add(p);
     }
 
@@ -96,18 +102,30 @@
     }
 
     public void appendLight(LightBase l) {
+        if (l == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mLights.add(l);
     }
 
     public void appendCamera(Camera c) {
+        if (c == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mCameras.add(c);
     }
 
     public void appendShader(FragmentShader f) {
+        if (f == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mFragmentShaders.add(f);
     }
 
     public void appendShader(VertexShader v) {
+        if (v == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mVertexShaders.add(v);
     }
 
@@ -120,6 +138,9 @@
     }
 
     public void appendRenderable(RenderableBase d) {
+        if (d == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mRenderables.add(d);
         mRenderableMap.put(d.getName(), d);
     }
@@ -133,6 +154,9 @@
     }
 
     public void appendTextures(Texture2D tex) {
+        if (tex == null) {
+            throw new RuntimeException("Adding null object");
+        }
         mTextures.add(tex);
     }
 
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
index f77f483..2e9a5eb 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java
@@ -29,8 +29,10 @@
 import java.util.regex.Pattern;
 
 import com.android.scenegraph.Camera;
+import com.android.scenegraph.FragmentShader;
 import com.android.scenegraph.MatrixTransform;
 import com.android.scenegraph.Scene;
+import com.android.scenegraph.VertexShader;
 import com.android.testapp.R;
 
 import android.content.res.Resources;
@@ -41,7 +43,6 @@
 import android.renderscript.Allocation.MipmapControl;
 import android.renderscript.Mesh;
 import android.renderscript.RenderScriptGL;
-import android.renderscript.Type.Builder;
 import android.util.Log;
 import android.view.SurfaceHolder;
 
@@ -71,8 +72,14 @@
     Scene mActiveScene;
     private static SceneManager sSceneManager;
 
-    private Allocation sDefault2D;
-    private Allocation sDefaultCube;
+    private Allocation mDefault2D;
+    private Allocation mDefaultCube;
+
+    private FragmentShader mColor;
+    private FragmentShader mTexture;
+    private VertexShader mDefaultVertex;
+
+    private RenderState mDefaultState;
 
     private static Allocation getDefault(boolean isCube) {
         final int dimension = 4;
@@ -101,20 +108,20 @@
         if (sSceneManager == null) {
             return null;
         }
-        if (sSceneManager.sDefault2D == null) {
-            sSceneManager.sDefault2D = getDefault(false);
+        if (sSceneManager.mDefault2D == null) {
+            sSceneManager.mDefault2D = getDefault(false);
         }
-        return sSceneManager.sDefault2D;
+        return sSceneManager.mDefault2D;
     }
 
     static Allocation getDefaultTexCube() {
         if (sSceneManager == null) {
             return null;
         }
-        if (sSceneManager.sDefaultCube == null) {
-            sSceneManager.sDefaultCube = getDefault(true);
+        if (sSceneManager.mDefaultCube == null) {
+            sSceneManager.mDefaultCube = getDefault(true);
         }
-        return sSceneManager.sDefaultCube;
+        return sSceneManager.mDefaultCube;
     }
 
     public static boolean isSDCardPath(String path) {
@@ -235,6 +242,10 @@
     public void setActiveScene(Scene s) {
         mActiveScene = s;
 
+        if (mActiveScene == null) {
+            return;
+        }
+
         // Do some sanity checking
         if (mActiveScene.getCameras().size() == 0) {
             Matrix4f camPos = new Matrix4f();
@@ -248,6 +259,8 @@
             cam.setTransform(cameraTransform);
             mActiveScene.appendCamera(cam);
         }
+
+        mActiveScene.appendShader(getDefaultVS());
     }
 
     static RenderScriptGL getRS() {
@@ -264,6 +277,114 @@
         return sSceneManager.mRes;
     }
 
+    // Provides the folowing inputs to fragment shader
+    // Assigned by default if nothing is present
+    // vec3 varWorldPos;
+    // vec3 varWorldNormal;
+    // vec2 varTex0;
+    public static VertexShader getDefaultVS() {
+        if (sSceneManager == null) {
+            return null;
+        }
+
+        if (sSceneManager.mDefaultVertex == null) {
+            RenderScriptGL rs = getRS();
+            Element.Builder b = new Element.Builder(rs);
+            b.add(Element.MATRIX_4X4(rs), "model");
+            Type.Builder objConstBuilder = new Type.Builder(rs, b.create());
+
+            b = new Element.Builder(rs);
+            b.add(Element.MATRIX_4X4(rs), "viewProj");
+            Type.Builder shaderConstBuilder = new Type.Builder(rs, b.create());
+
+            b = new Element.Builder(rs);
+            b.add(Element.F32_4(rs), "position");
+            b.add(Element.F32_2(rs), "texture0");
+            b.add(Element.F32_3(rs), "normal");
+            Element defaultIn = b.create();
+
+            final String code = "\n" +
+                "varying vec3 varWorldPos;\n" +
+                "varying vec3 varWorldNormal;\n" +
+                "varying vec2 varTex0;\n" +
+                "void main() {" +
+                "   vec4 objPos = ATTRIB_position;\n" +
+                "   vec4 worldPos = UNI_model * objPos;\n" +
+                "   gl_Position = UNI_viewProj * worldPos;\n" +
+                "   mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);\n" +
+                "   vec3 worldNorm = model3 * ATTRIB_normal;\n" +
+                "   varWorldPos = worldPos.xyz;\n" +
+                "   varWorldNormal = worldNorm;\n" +
+                "   varTex0 = ATTRIB_texture0;\n" +
+                "}\n";
+
+            VertexShader.Builder sb = new VertexShader.Builder(rs);
+            sb.addInput(defaultIn);
+            sb.setObjectConst(objConstBuilder.setX(1).create());
+            sb.setShaderConst(shaderConstBuilder.setX(1).create());
+            sb.setShader(code);
+            sSceneManager.mDefaultVertex = sb.create();
+        }
+
+        return sSceneManager.mDefaultVertex;
+    }
+
+    public static FragmentShader getColorFS() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        if (sSceneManager.mColor == null) {
+            RenderScriptGL rs = getRS();
+            Element.Builder b = new Element.Builder(rs);
+            b.add(Element.F32_4(rs), "color");
+            Type.Builder objConstBuilder = new Type.Builder(rs, b.create());
+
+            final String code = "\n" +
+                "varying vec2 varTex0;\n" +
+                "void main() {\n" +
+                "   lowp vec4 col = texture2D(UNI_Tex0, varTex0).rgba;\n" +
+                "   gl_FragColor = col;\n" +
+                "}\n";
+            FragmentShader.Builder fb = new FragmentShader.Builder(rs);
+            fb.setShader(code);
+            fb.setObjectConst(objConstBuilder.create());
+            sSceneManager.mColor = fb.create();
+        }
+
+        return sSceneManager.mColor;
+    }
+
+    public static FragmentShader getTextureFS() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        if (sSceneManager.mTexture == null) {
+            RenderScriptGL rs = getRS();
+            final String code = "\n" +
+                "varying vec2 varTex0;\n" +
+                "void main() {\n" +
+                "   lowp vec4 col = UNI_color;\n" +
+                "   gl_FragColor = col;\n" +
+                "}\n";
+            FragmentShader.Builder fb = new FragmentShader.Builder(rs);
+            fb.setShader(code);
+            fb.addTexture(Program.TextureType.TEXTURE_2D, "Tex0");
+            sSceneManager.mTexture = fb.create();
+        }
+
+        return sSceneManager.mTexture;
+    }
+
+    static RenderState getDefaultState() {
+        if (sSceneManager == null) {
+            return null;
+        }
+        if (sSceneManager.mDefaultState == null) {
+            sSceneManager.mDefaultState = new RenderState(getDefaultVS(), getColorFS(), null, null);
+        }
+        return sSceneManager.mDefaultState;
+    }
+
     public static SceneManager getInstance() {
         if (sSceneManager == null) {
             sSceneManager = new SceneManager();
@@ -321,6 +442,14 @@
         mRes = res;
         mAllocationMap = new HashMap<String, Allocation>();
 
+        mQuad = null;
+        mDefault2D = null;
+        mDefaultCube = null;
+        mDefaultVertex = null;
+        mColor = null;
+        mTexture = null;
+        mDefaultState = null;
+
         mExportScript = new ScriptC_export(rs, res, R.raw.export);
 
         mTransformScript = new ScriptC_transform(rs, res, R.raw.transform);
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
index 8dea535..3dd41ca 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java
@@ -75,7 +75,7 @@
             // Make one if it's not there
             if (matchingParam == null) {
                 if (subElem.getDataType() == Element.DataType.FLOAT_32) {
-                    matchingParam = new Float4Param(inputName);
+                    matchingParam = new Float4Param(inputName, 0.5f, 0.5f, 0.5f, 0.5f);
                 } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) {
                     TransformParam trParam = new TransformParam(inputName);
                     trParam.setTransform(transform);
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
index f7d0e6d..4efaff7 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java
@@ -44,6 +44,11 @@
             return this;
         }
 
+        public Builder setShader(String code) {
+            mBuilder.setShader(code);
+            return this;
+        }
+
         public Builder setObjectConst(Type type) {
             mShader.mPerObjConstants = type;
             return this;
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
index 7bf7812..f159e85 100644
--- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
+++ b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java
@@ -149,34 +149,27 @@
     }
 
     private void initPaintShaders() {
-        ScriptField_ModelParams objConst = new ScriptField_ModelParams(mRS, 1);
-        ScriptField_ViewProjParams shaderConst = new ScriptField_ViewProjParams(mRS, 1);
+        mGenericV = SceneManager.getDefaultVS();
 
-        VertexShader.Builder vb = new VertexShader.Builder(mRS);
-        vb.addInput(ScriptField_VertexShaderInputs.createElement(mRS));
-        vb.setShader(mRes, R.raw.shader2v);
-        vb.setObjectConst(objConst.getAllocation().getType());
-        vb.setShaderConst(shaderConst.getAllocation().getType());
-        mGenericV = vb.create();
+        ScriptField_CameraParams camParams = new ScriptField_CameraParams(mRS, 1);
+        Type camParamType = camParams.getAllocation().getType();
+        ScriptField_LightParams lightParams = new ScriptField_LightParams(mRS, 1);
 
-        ScriptField_CameraParams fsConst = new ScriptField_CameraParams(mRS, 1);
-        ScriptField_LightParams fsConst2 = new ScriptField_LightParams(mRS, 1);
-
-        mPaintF = createFromResource(R.raw.paintf, true, fsConst.getAllocation().getType());
+        mPaintF = createFromResource(R.raw.paintf, true, camParamType);
         // Assign a reflection map
         TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png");
         mPaintF.appendSourceParams(new TextureParam("reflection", envCube));
 
-        mAluminumF = createFromResource(R.raw.metal, true, fsConst.getAllocation().getType());
+        mAluminumF = createFromResource(R.raw.metal, true, camParamType);
         TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png");
         mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube));
 
-        mPlasticF = createFromResource(R.raw.plastic, false, fsConst.getAllocation().getType());
-        mDiffuseF = createFromResource(R.raw.diffuse, false, fsConst.getAllocation().getType());
-        mTextureF = createFromResource(R.raw.texture, false, fsConst.getAllocation().getType());
+        mPlasticF = createFromResource(R.raw.plastic, false, camParamType);
+        mDiffuseF = createFromResource(R.raw.diffuse, false, camParamType);
+        mTextureF = SceneManager.getTextureFS();
 
         FragmentShader.Builder fb = new FragmentShader.Builder(mRS);
-        fb.setObjectConst(fsConst2.getAllocation().getType());
+        fb.setObjectConst(lightParams.getAllocation().getType());
         fb.setShader(mRes, R.raw.plastic_lights);
         mLightsF = fb.create();
 
@@ -214,7 +207,6 @@
         mActiveScene.appendShader(mPlasticF);
         mActiveScene.appendShader(mDiffuseF);
         mActiveScene.appendShader(mTextureF);
-        mActiveScene.appendShader(mGenericV);
     }
 
     public void prepareToRender(Scene s) {
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index 31e2ec5..88794c2 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -24,7 +24,7 @@
 LOCAL_MODULE_TAGS := optional
 LOCAL_MODULE := backup_helper_test
 LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_SHARED_LIBRARIES := libutils
+LOCAL_SHARED_LIBRARIES := libandroidfw libutils
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/tests/backup/backup_helper_test.cpp b/tests/backup/backup_helper_test.cpp
index 04358ad..b5f6ff5 100644
--- a/tests/backup/backup_helper_test.cpp
+++ b/tests/backup/backup_helper_test.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <utils/BackupHelpers.h>
+#include <androidfw/BackupHelpers.h>
 
 #include <stdio.h>
 #include <string.h>
diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h
index 1c653e1..5924952 100644
--- a/tools/aapt/AaptAssets.h
+++ b/tools/aapt/AaptAssets.h
@@ -7,14 +7,14 @@
 #define __AAPT_ASSETS_H
 
 #include <stdlib.h>
-#include <utils/AssetManager.h>
+#include <androidfw/AssetManager.h>
+#include <androidfw/ResourceTypes.h>
 #include <utils/KeyedVector.h>
-#include <utils/String8.h>
-#include <utils/ResourceTypes.h>
+#include <utils/RefBase.h>
 #include <utils/SortedVector.h>
 #include <utils/String8.h>
+#include <utils/String8.h>
 #include <utils/Vector.h>
-#include <utils/RefBase.h>
 #include "ZipFile.h"
 
 #include "Bundle.h"
diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk
index cb55a9c..d0a81dc 100644
--- a/tools/aapt/Android.mk
+++ b/tools/aapt/Android.mk
@@ -38,6 +38,7 @@
 #LOCAL_WHOLE_STATIC_LIBRARIES := 
 LOCAL_STATIC_LIBRARIES := \
 	libhost \
+	libandroidfw \
 	libutils \
 	libcutils \
 	libexpat \
diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp
index ffbe875..6402e3c 100644
--- a/tools/aapt/Images.cpp
+++ b/tools/aapt/Images.cpp
@@ -8,7 +8,7 @@
 
 #include "Images.h"
 
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 #include <utils/ByteOrder.h>
 
 #include <png.h>
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 7a0499c..0c0b2ea 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -9,8 +9,8 @@
 #include "XMLNode.h"
 #include "ResourceFilter.h"
 
+#include <androidfw/ResourceTypes.h>
 #include <utils/ByteOrder.h>
-#include <utils/ResourceTypes.h>
 #include <stdarg.h>
 
 #define NOISY(x) //x
diff --git a/tools/aapt/StringPool.h b/tools/aapt/StringPool.h
index 255bdbf..86044ed 100644
--- a/tools/aapt/StringPool.h
+++ b/tools/aapt/StringPool.h
@@ -10,7 +10,7 @@
 #include "Main.h"
 #include "AaptAssets.h"
 
-#include <utils/ResourceTypes.h>
+#include <androidfw/ResourceTypes.h>
 #include <utils/String16.h>
 #include <utils/TextOutput.h>
 
diff --git a/tools/aapt/ZipFile.cpp b/tools/aapt/ZipFile.cpp
index 0705be3..8057068 100644
--- a/tools/aapt/ZipFile.cpp
+++ b/tools/aapt/ZipFile.cpp
@@ -20,7 +20,7 @@
 
 #define LOG_TAG "zip"
 
-#include <utils/ZipUtils.h>
+#include <androidfw/ZipUtils.h>
 #include <utils/Log.h>
 
 #include "ZipFile.h"
diff --git a/tools/aidl/Type.cpp b/tools/aidl/Type.cpp
index 42e1226..d572af6 100755
--- a/tools/aidl/Type.cpp
+++ b/tools/aidl/Type.cpp
@@ -123,7 +123,7 @@
     RPC_DATA_TYPE = new RpcDataType();
     NAMES.Add(RPC_DATA_TYPE);
 
-    RPC_ERROR_TYPE = new UserDataType("com.android.athome.rpc", "RpcError",
+    RPC_ERROR_TYPE = new UserDataType("android.support.place.rpc", "RpcError",
                                     true, __FILE__, __LINE__);
     NAMES.Add(RPC_ERROR_TYPE);
 
@@ -1234,7 +1234,7 @@
 // ================================================================
 
 RpcDataType::RpcDataType()
-    :UserDataType("com.android.athome.rpc", "RpcData", true, true, true)
+    :UserDataType("android.support.place.rpc", "RpcData", true, true, true)
 {
 }
 
diff --git a/tools/aidl/generate_java_rpc.cpp b/tools/aidl/generate_java_rpc.cpp
index ecff3a1..e5fa076 100644
--- a/tools/aidl/generate_java_rpc.cpp
+++ b/tools/aidl/generate_java_rpc.cpp
@@ -7,26 +7,26 @@
 
 Type* SERVICE_CONTEXT_TYPE = new Type("android.content",
         "Context", Type::BUILT_IN, false, false, false);
-Type* PRESENTER_BASE_TYPE = new Type("com.android.athome.connector",
+Type* PRESENTER_BASE_TYPE = new Type("android.support.place.connector",
         "EventListener", Type::BUILT_IN, false, false, false);
-Type* PRESENTER_LISTENER_BASE_TYPE = new Type("com.android.athome.connector",
+Type* PRESENTER_LISTENER_BASE_TYPE = new Type("android.support.place.connector",
         "EventListener.Listener", Type::BUILT_IN, false, false, false);
-Type* RPC_BROKER_TYPE = new Type("com.android.athome.connector", "Broker",
+Type* RPC_BROKER_TYPE = new Type("android.support.place.connector", "Broker",
         Type::BUILT_IN, false, false, false);
 Type* RPC_CONTAINER_TYPE = new Type("com.android.athome.connector", "ConnectorContainer",
         Type::BUILT_IN, false, false, false);
 Type* PLACE_INFO_TYPE = new Type("android.support.place.connector", "PlaceInfo",
         Type::BUILT_IN, false, false, false);
 // TODO: Just use Endpoint, so this works for all endpoints.
-Type* RPC_CONNECTOR_TYPE = new Type("com.android.athome.connector", "Connector",
+Type* RPC_CONNECTOR_TYPE = new Type("android.support.place.connector", "Connector",
         Type::BUILT_IN, false, false, false);
-Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("com.android.athome.rpc",
+Type* RPC_ENDPOINT_INFO_TYPE = new UserDataType("android.support.place.rpc",
         "EndpointInfo", true, __FILE__, __LINE__);
-Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("com.android.athome.rpc", "RpcResultHandler",
+Type* RPC_RESULT_HANDLER_TYPE = new UserDataType("android.support.place.rpc", "RpcResultHandler",
         true, __FILE__, __LINE__);
-Type* RPC_ERROR_LISTENER_TYPE = new Type("com.android.athome.rpc", "RpcErrorHandler",
+Type* RPC_ERROR_LISTENER_TYPE = new Type("android.support.place.rpc", "RpcErrorHandler",
         Type::BUILT_IN, false, false, false);
-Type* RPC_CONTEXT_TYPE = new UserDataType("com.android.athome.rpc", "RpcContext", true,
+Type* RPC_CONTEXT_TYPE = new UserDataType("android.support.place.rpc", "RpcContext", true,
         __FILE__, __LINE__);
 
 static void generate_create_from_data(Type* t, StatementBlock* addTo, const string& key,
diff --git a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
index 96de51c..97d9969 100644
--- a/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
+++ b/tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
@@ -29,7 +29,7 @@
 
     public static void setAttachInfo(View view) {
         AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
-                new Handler(), null);
+                new ViewRootImpl(view.getContext()), new Handler(), null);
         info.mHasWindowFocus = true;
         info.mWindowVisibility = View.VISIBLE;
         info.mInTouchMode = false; // this is so that we can display selections.
diff --git a/tools/makekeycodes/makekeycodes.cpp b/tools/makekeycodes/makekeycodes.cpp
index 16df774..6ffbfb8 100644
--- a/tools/makekeycodes/makekeycodes.cpp
+++ b/tools/makekeycodes/makekeycodes.cpp
@@ -1,5 +1,21 @@
+/*
+ * Copyright (C) 2012 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.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 #include <stdio.h>
-#include <ui/KeycodeLabels.h>
+#include <androidfw/KeycodeLabels.h>
 
 int
 main(int argc, char** argv)
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index 72a9858..dd57ae6 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -19,6 +19,7 @@
 
 LOCAL_STATIC_LIBRARIES := \
 	libutils \
+	libandroidfw \
 	libcutils
 
 ifeq ($(HOST_OS),linux)
diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp
index 932dbec..b2152e8 100644
--- a/tools/obbtool/Main.cpp
+++ b/tools/obbtool/Main.cpp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include <utils/ObbFile.h>
+#include <androidfw/ObbFile.h>
 #include <utils/String8.h>
 
 #include <getopt.h>
diff --git a/tools/validatekeymaps/Android.mk b/tools/validatekeymaps/Android.mk
index 1368a07..fce2e93 100644
--- a/tools/validatekeymaps/Android.mk
+++ b/tools/validatekeymaps/Android.mk
@@ -18,7 +18,7 @@
 #LOCAL_C_INCLUDES +=
 
 LOCAL_STATIC_LIBRARIES := \
-	libui \
+	libandroidfw \
 	libutils \
 	libcutils
 
diff --git a/tools/validatekeymaps/Main.cpp b/tools/validatekeymaps/Main.cpp
index 8ab9b6a..3cc2467 100644
--- a/tools/validatekeymaps/Main.cpp
+++ b/tools/validatekeymaps/Main.cpp
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include <ui/KeyCharacterMap.h>
-#include <ui/KeyLayoutMap.h>
-#include <ui/VirtualKeyMap.h>
+#include <androidfw/KeyCharacterMap.h>
+#include <androidfw/KeyLayoutMap.h>
+#include <androidfw/VirtualKeyMap.h>
 #include <utils/PropertyMap.h>
 #include <utils/String8.h>
 
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 0134456..1b64f3e 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1754,7 +1754,9 @@
          * If we've exceeded the maximum number of retries for DHCP
          * to a given network, disable the network
          */
-        if (++mReconnectCount > getMaxDhcpRetries()) {
+        int maxRetries = getMaxDhcpRetries();
+        // maxRetries == 0 means keep trying forever
+        if (maxRetries > 0 && ++mReconnectCount > maxRetries) {
             loge("Failed " +
                     mReconnectCount + " times, Disabling " + mLastNetworkId);
             mWifiConfigStore.disableNetwork(mLastNetworkId,