Merge "Add RequiresFeature annotation."
diff --git a/Android.mk b/Android.mk
index 3b8d6a8..58e21ff 100644
--- a/Android.mk
+++ b/Android.mk
@@ -793,6 +793,8 @@
     $(call all-proto-files-under, core/proto) \
     $(call all-proto-files-under, libs/incident/proto) \
     $(call all-proto-files-under, cmds/statsd/src)
+# b/72714520
+LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF
 include $(BUILD_HOST_JAVA_LIBRARY)
 
 # ====  java proto device library (for test only)  ==============================
diff --git a/api/current.txt b/api/current.txt
index df18f10..a70363d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27998,23 +27998,23 @@
     method public int updateNetwork(android.net.wifi.WifiConfiguration);
     field public static final java.lang.String ACTION_PICK_WIFI_NETWORK = "android.net.wifi.PICK_WIFI_NETWORK";
     field public static final java.lang.String ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE = "android.net.wifi.action.REQUEST_SCAN_ALWAYS_AVAILABLE";
-    field public static final int ERROR_AUTHENTICATING = 1; // 0x1
+    field public static final deprecated int ERROR_AUTHENTICATING = 1; // 0x1
     field public static final deprecated java.lang.String EXTRA_BSSID = "bssid";
     field public static final java.lang.String EXTRA_NETWORK_INFO = "networkInfo";
     field public static final java.lang.String EXTRA_NEW_RSSI = "newRssi";
-    field public static final java.lang.String EXTRA_NEW_STATE = "newState";
+    field public static final deprecated java.lang.String EXTRA_NEW_STATE = "newState";
     field public static final java.lang.String EXTRA_PREVIOUS_WIFI_STATE = "previous_wifi_state";
     field public static final java.lang.String EXTRA_RESULTS_UPDATED = "resultsUpdated";
-    field public static final java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
-    field public static final java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
+    field public static final deprecated java.lang.String EXTRA_SUPPLICANT_CONNECTED = "connected";
+    field public static final deprecated java.lang.String EXTRA_SUPPLICANT_ERROR = "supplicantError";
     field public static final deprecated java.lang.String EXTRA_WIFI_INFO = "wifiInfo";
     field public static final java.lang.String EXTRA_WIFI_STATE = "wifi_state";
     field public static final java.lang.String NETWORK_IDS_CHANGED_ACTION = "android.net.wifi.NETWORK_IDS_CHANGED";
     field public static final java.lang.String NETWORK_STATE_CHANGED_ACTION = "android.net.wifi.STATE_CHANGE";
     field public static final java.lang.String RSSI_CHANGED_ACTION = "android.net.wifi.RSSI_CHANGED";
     field public static final java.lang.String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
-    field public static final java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
-    field public static final java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
+    field public static final deprecated java.lang.String SUPPLICANT_CONNECTION_CHANGE_ACTION = "android.net.wifi.supplicant.CONNECTION_CHANGE";
+    field public static final deprecated java.lang.String SUPPLICANT_STATE_CHANGED_ACTION = "android.net.wifi.supplicant.STATE_CHANGE";
     field public static final int WIFI_MODE_FULL = 1; // 0x1
     field public static final int WIFI_MODE_FULL_HIGH_PERF = 3; // 0x3
     field public static final int WIFI_MODE_SCAN_ONLY = 2; // 0x2
@@ -28069,20 +28069,21 @@
     method public abstract deprecated void onSucceeded();
   }
 
-  public class WpsInfo implements android.os.Parcelable {
-    ctor public WpsInfo();
-    ctor public WpsInfo(android.net.wifi.WpsInfo);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public java.lang.String BSSID;
-    field public static final android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
-    field public static final int DISPLAY = 1; // 0x1
-    field public static final int INVALID = 4; // 0x4
-    field public static final int KEYPAD = 2; // 0x2
-    field public static final int LABEL = 3; // 0x3
-    field public static final int PBC = 0; // 0x0
-    field public java.lang.String pin;
-    field public int setup;
+  public deprecated class WpsInfo implements android.os.Parcelable {
+    ctor public deprecated WpsInfo();
+    ctor public deprecated WpsInfo(android.net.wifi.WpsInfo);
+    method public deprecated int describeContents();
+    method public deprecated java.lang.String toString();
+    method public deprecated void writeToParcel(android.os.Parcel, int);
+    field public deprecated java.lang.String BSSID;
+    field public static final deprecated android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR;
+    field public static final deprecated int DISPLAY = 1; // 0x1
+    field public static final deprecated int INVALID = 4; // 0x4
+    field public static final deprecated int KEYPAD = 2; // 0x2
+    field public static final deprecated int LABEL = 3; // 0x3
+    field public static final deprecated int PBC = 0; // 0x0
+    field public deprecated java.lang.String pin;
+    field public deprecated int setup;
   }
 
 }
@@ -36640,6 +36641,7 @@
     field public static final deprecated java.lang.String RADIO_NFC = "nfc";
     field public static final deprecated java.lang.String RADIO_WIFI = "wifi";
     field public static final java.lang.String RINGTONE = "ringtone";
+    field public static final java.lang.String RTT_CALLING_MODE = "rtt_calling_mode";
     field public static final java.lang.String SCREEN_BRIGHTNESS = "screen_brightness";
     field public static final java.lang.String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
     field public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; // 0x1
@@ -38449,6 +38451,7 @@
     method public boolean isRandomizedEncryptionRequired();
     method public boolean isStrongBoxBacked();
     method public boolean isTrustedUserPresenceRequired();
+    method public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
     method public boolean isUserConfirmationRequired();
@@ -38476,6 +38479,7 @@
     method public android.security.keystore.KeyGenParameterSpec.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setSignaturePaddings(java.lang.String...);
     method public android.security.keystore.KeyGenParameterSpec.Builder setTrustedUserPresenceRequired(boolean);
+    method public android.security.keystore.KeyGenParameterSpec.Builder setUnlockedDeviceRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationRequired(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyGenParameterSpec.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -38567,6 +38571,8 @@
     method public boolean isDigestsSpecified();
     method public boolean isInvalidatedByBiometricEnrollment();
     method public boolean isRandomizedEncryptionRequired();
+    method public boolean isTrustedUserPresenceRequired();
+    method public boolean isUnlockedDeviceRequired();
     method public boolean isUserAuthenticationRequired();
     method public boolean isUserAuthenticationValidWhileOnBody();
     method public boolean isUserConfirmationRequired();
@@ -38585,6 +38591,8 @@
     method public android.security.keystore.KeyProtection.Builder setKeyValidityStart(java.util.Date);
     method public android.security.keystore.KeyProtection.Builder setRandomizedEncryptionRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setSignaturePaddings(java.lang.String...);
+    method public android.security.keystore.KeyProtection.Builder setTrustedUserPresenceRequired(boolean);
+    method public android.security.keystore.KeyProtection.Builder setUnlockedDeviceRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationRequired(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidWhileOnBody(boolean);
     method public android.security.keystore.KeyProtection.Builder setUserAuthenticationValidityDurationSeconds(int);
@@ -40645,6 +40653,7 @@
     field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 128; // 0x80
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
     field public static final int PROPERTY_IS_EXTERNAL_CALL = 64; // 0x40
+    field public static final int PROPERTY_RTT = 1024; // 0x400
     field public static final int PROPERTY_SELF_MANAGED = 256; // 0x100
     field public static final int PROPERTY_WIFI = 8; // 0x8
   }
@@ -44487,10 +44496,12 @@
 
   public class TypefaceSpan extends android.text.style.MetricAffectingSpan implements android.text.ParcelableSpan {
     ctor public TypefaceSpan(java.lang.String);
+    ctor public TypefaceSpan(android.graphics.Typeface);
     ctor public TypefaceSpan(android.os.Parcel);
     method public int describeContents();
     method public java.lang.String getFamily();
     method public int getSpanTypeId();
+    method public android.graphics.Typeface getTypeface();
     method public void updateDrawState(android.text.TextPaint);
     method public void updateMeasureState(android.text.TextPaint);
     method public void writeToParcel(android.os.Parcel, int);
@@ -49795,6 +49806,8 @@
     method public boolean isFieldClassificationEnabled();
     method public void notifyValueChanged(android.view.View);
     method public void notifyValueChanged(android.view.View, int, android.view.autofill.AutofillValue);
+    method public void notifyViewClicked(android.view.View);
+    method public void notifyViewClicked(android.view.View, int);
     method public void notifyViewEntered(android.view.View);
     method public void notifyViewEntered(android.view.View, int, android.graphics.Rect);
     method public void notifyViewExited(android.view.View);
@@ -50302,6 +50315,7 @@
     method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence);
     method public default java.util.Collection<java.lang.String> getEntitiesForPreset(int);
     method public default android.view.textclassifier.logging.Logger getLogger(android.view.textclassifier.logging.Logger.Config);
+    method public default int getMaxGenerateLinksTextLength();
     method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
     method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int);
     method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
@@ -50756,41 +50770,37 @@
   }
 
   public class TracingConfig {
-    ctor public TracingConfig(int);
-    ctor public TracingConfig(int, java.lang.String, int);
-    method public java.lang.String getCustomCategoryPattern();
-    method public int getPresetCategories();
+    method public java.util.List<java.lang.String> getCustomIncludedCategories();
+    method public int getPredefinedCategories();
     method public int getTracingMode();
-    field public static final int CATEGORIES_FRAME_VIEWER = 4; // 0x4
-    field public static final int CATEGORIES_INPUT_LATENCY = 1; // 0x1
-    field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3; // 0x3
-    field public static final int CATEGORIES_NONE = -1; // 0xffffffff
-    field public static final int CATEGORIES_RENDERING = 2; // 0x2
-    field public static final int CATEGORIES_WEB_DEVELOPER = 0; // 0x0
+    field public static final int CATEGORIES_ALL = 1; // 0x1
+    field public static final int CATEGORIES_ANDROID_WEBVIEW = 2; // 0x2
+    field public static final int CATEGORIES_FRAME_VIEWER = 64; // 0x40
+    field public static final int CATEGORIES_INPUT_LATENCY = 8; // 0x8
+    field public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 32; // 0x20
+    field public static final int CATEGORIES_NONE = 0; // 0x0
+    field public static final int CATEGORIES_RENDERING = 16; // 0x10
+    field public static final int CATEGORIES_WEB_DEVELOPER = 4; // 0x4
     field public static final int RECORD_CONTINUOUSLY = 1; // 0x1
-    field public static final int RECORD_TO_CONSOLE = 3; // 0x3
     field public static final int RECORD_UNTIL_FULL = 0; // 0x0
     field public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2; // 0x2
   }
 
+  public static class TracingConfig.Builder {
+    ctor public TracingConfig.Builder();
+    method public android.webkit.TracingConfig.Builder addCategories(int...);
+    method public android.webkit.TracingConfig.Builder addCategories(java.lang.String...);
+    method public android.webkit.TracingConfig.Builder addCategories(java.util.Collection<java.lang.String>);
+    method public android.webkit.TracingConfig build();
+    method public android.webkit.TracingConfig.Builder setTracingMode(int);
+  }
+
   public abstract class TracingController {
     ctor public TracingController();
     method public static android.webkit.TracingController getInstance();
     method public abstract boolean isTracing();
-    method public abstract boolean start(android.webkit.TracingConfig);
-    method public abstract boolean stop();
-    method public abstract boolean stopAndFlush(android.webkit.TracingController.TracingOutputStream, android.os.Handler);
-  }
-
-  public static abstract interface TracingController.TracingOutputStream {
-    method public abstract void complete();
-    method public abstract void write(byte[]);
-  }
-
-  public class TracingFileOutputStream implements android.webkit.TracingController.TracingOutputStream {
-    ctor public TracingFileOutputStream(java.lang.String) throws java.io.FileNotFoundException;
-    method public void complete();
-    method public void write(byte[]);
+    method public abstract void start(android.webkit.TracingConfig);
+    method public abstract boolean stop(java.io.OutputStream, java.util.concurrent.Executor);
   }
 
   public final class URLUtil {
diff --git a/api/test-current.txt b/api/test-current.txt
index 9bfc105..2e47e00 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1061,6 +1061,7 @@
 
   public final class AutofillId implements android.os.Parcelable {
     ctor public AutofillId(int);
+    ctor public AutofillId(android.view.autofill.AutofillId, int);
   }
 
 }
diff --git a/cmds/incidentd/.clang-format b/cmds/incidentd/.clang-format
new file mode 100644
index 0000000..6fa5b47
--- /dev/null
+++ b/cmds/incidentd/.clang-format
@@ -0,0 +1,17 @@
+BasedOnStyle: Google
+AllowShortIfStatementsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+BinPackArguments: true
+BinPackParameters: true
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+ContinuationIndentWidth: 8
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+AccessModifierOffset: -4
+IncludeCategories:
+  - Regex:    '^"Log\.h"'
+    Priority:    -1
diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk
index 23cd2af..d2d24c8 100644
--- a/cmds/incidentd/Android.mk
+++ b/cmds/incidentd/Android.mk
@@ -32,7 +32,7 @@
         src/Privacy.cpp \
         src/Reporter.cpp \
         src/Section.cpp \
-        src/io_util.cpp \
+        src/incidentd_util.cpp \
         src/main.cpp \
         src/report_directory.cpp
 
@@ -116,7 +116,7 @@
     src/Privacy.cpp \
     src/Reporter.cpp \
     src/Section.cpp \
-    src/io_util.cpp \
+    src/incidentd_util.cpp \
     src/report_directory.cpp \
     tests/section_list.cpp \
     tests/PrivacyBuffer_test.cpp \
diff --git a/cmds/incidentd/README.md b/cmds/incidentd/README.md
index 71c6deb..1730a640 100644
--- a/cmds/incidentd/README.md
+++ b/cmds/incidentd/README.md
@@ -20,4 +20,8 @@
 
 ```
 root$ atest incidentd_test
-```
\ No newline at end of file
+```
+
+Use clang-format to style the file
+
+clang-format -style=file -i <file list>
\ No newline at end of file
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 0fff4e6..883924c8 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
 
 #include "FdBuffer.h"
 
@@ -26,30 +25,16 @@
 #include <unistd.h>
 #include <wait.h>
 
-const bool DEBUG = false;
-const ssize_t BUFFER_SIZE = 16 * 1024; // 16 KB
-const ssize_t MAX_BUFFER_COUNT = 256; // 4 MB max
+const ssize_t BUFFER_SIZE = 16 * 1024;  // 16 KB
+const ssize_t MAX_BUFFER_COUNT = 256;   // 4 MB max
 
 FdBuffer::FdBuffer()
-    :mBuffer(BUFFER_SIZE),
-     mStartTime(-1),
-     mFinishTime(-1),
-     mTimedOut(false),
-     mTruncated(false)
-{
-}
+    : mBuffer(BUFFER_SIZE), mStartTime(-1), mFinishTime(-1), mTimedOut(false), mTruncated(false) {}
 
-FdBuffer::~FdBuffer()
-{
-}
+FdBuffer::~FdBuffer() {}
 
-status_t
-FdBuffer::read(int fd, int64_t timeout)
-{
-    struct pollfd pfds = {
-        .fd = fd,
-        .events = POLLIN
-    };
+status_t FdBuffer::read(int fd, int64_t timeout) {
+    struct pollfd pfds = {.fd = fd, .events = POLLIN};
     mStartTime = uptimeMillis();
 
     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
@@ -63,22 +48,22 @@
 
         int64_t remainingTime = (mStartTime + timeout) - uptimeMillis();
         if (remainingTime <= 0) {
-            if (DEBUG) ALOGD("timed out due to long read");
+            VLOG("timed out due to long read");
             mTimedOut = true;
             break;
         }
 
         int count = poll(&pfds, 1, remainingTime);
         if (count == 0) {
-            if (DEBUG) ALOGD("timed out due to block calling poll");
+            VLOG("timed out due to block calling poll");
             mTimedOut = true;
             break;
         } else if (count < 0) {
-            if (DEBUG) ALOGD("poll failed: %s", strerror(errno));
+            VLOG("poll failed: %s", strerror(errno));
             return -errno;
         } else {
             if ((pfds.revents & POLLERR) != 0) {
-                if (DEBUG) ALOGD("return event has error %s", strerror(errno));
+                VLOG("return event has error %s", strerror(errno));
                 return errno != 0 ? -errno : UNKNOWN_ERROR;
             } else {
                 ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
@@ -86,7 +71,7 @@
                     if (errno == EAGAIN || errno == EWOULDBLOCK) {
                         continue;
                     } else {
-                        if (DEBUG) ALOGD("Fail to read %d: %s", fd, strerror(errno));
+                        VLOG("Fail to read %d: %s", fd, strerror(errno));
                         return -errno;
                     }
                 } else if (amt == 0) {
@@ -100,13 +85,12 @@
     return NO_ERROR;
 }
 
-status_t
-FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, const bool isSysfs)
-{
+status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
+                                             const bool isSysfs) {
     struct pollfd pfds[] = {
-        { .fd = fd,     .events = POLLIN  },
-        { .fd = toFd,   .events = POLLOUT },
-        { .fd = fromFd, .events = POLLIN  },
+            {.fd = fd, .events = POLLIN},
+            {.fd = toFd, .events = POLLOUT},
+            {.fd = fromFd, .events = POLLIN},
     };
 
     mStartTime = uptimeMillis();
@@ -131,7 +115,7 @@
 
         int64_t remainingTime = (mStartTime + timeoutMs) - uptimeMillis();
         if (remainingTime <= 0) {
-            if (DEBUG) ALOGD("timed out due to long read");
+            VLOG("timed out due to long read");
             mTimedOut = true;
             break;
         }
@@ -139,11 +123,11 @@
         // wait for any pfds to be ready to perform IO
         int count = poll(pfds, 3, remainingTime);
         if (count == 0) {
-            if (DEBUG) ALOGD("timed out due to block calling poll");
+            VLOG("timed out due to block calling poll");
             mTimedOut = true;
             break;
         } else if (count < 0) {
-            if (DEBUG) ALOGD("Fail to poll: %s", strerror(errno));
+            VLOG("Fail to poll: %s", strerror(errno));
             return -errno;
         }
 
@@ -151,10 +135,10 @@
         for (int i = 0; i < 3; ++i) {
             if ((pfds[i].revents & POLLERR) != 0) {
                 if (i == 0 && isSysfs) {
-                    if (DEBUG) ALOGD("fd %d is sysfs, ignore its POLLERR return value", fd);
+                    VLOG("fd %d is sysfs, ignore its POLLERR return value", fd);
                     continue;
                 }
-                if (DEBUG) ALOGD("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
+                VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
                 return errno != 0 ? -errno : UNKNOWN_ERROR;
             }
         }
@@ -169,9 +153,9 @@
             }
             if (amt < 0) {
                 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
-                    if (DEBUG) ALOGD("Fail to read fd %d: %s", fd, strerror(errno));
+                    VLOG("Fail to read fd %d: %s", fd, strerror(errno));
                     return -errno;
-                } // otherwise just continue
+                }                   // otherwise just continue
             } else if (amt == 0) {  // reach EOF so don't have to poll pfds[0].
                 ::close(pfds[0].fd);
                 pfds[0].fd = -1;
@@ -191,9 +175,9 @@
             }
             if (amt < 0) {
                 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
-                    if (DEBUG) ALOGD("Fail to write toFd %d: %s", toFd, strerror(errno));
+                    VLOG("Fail to write toFd %d: %s", toFd, strerror(errno));
                     return -errno;
-                } // otherwise just continue
+                }  // otherwise just continue
             } else {
                 wpos += amt;
                 cirSize -= amt;
@@ -218,9 +202,9 @@
         ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
         if (amt < 0) {
             if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
-                if (DEBUG) ALOGD("Fail to read fromFd %d: %s", fromFd, strerror(errno));
+                VLOG("Fail to read fromFd %d: %s", fromFd, strerror(errno));
                 return -errno;
-            } // otherwise just continue
+            }  // otherwise just continue
         } else if (amt == 0) {
             break;
         } else {
@@ -232,14 +216,6 @@
     return NO_ERROR;
 }
 
-size_t
-FdBuffer::size() const
-{
-    return mBuffer.size();
-}
+size_t FdBuffer::size() const { return mBuffer.size(); }
 
-EncodedBuffer::iterator
-FdBuffer::data() const
-{
-    return mBuffer.begin();
-}
+EncodedBuffer::iterator FdBuffer::data() const { return mBuffer.begin(); }
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index 48dc855..5bfa093 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef FD_BUFFER_H
 #define FD_BUFFER_H
@@ -27,8 +28,7 @@
 /**
  * Reads a file into a buffer, and then writes that data to an FdSet.
  */
-class FdBuffer
-{
+class FdBuffer {
 public:
     FdBuffer();
     ~FdBuffer();
@@ -50,7 +50,8 @@
      *
      * Poll will return POLLERR if fd is from sysfs, handle this edge case.
      */
-    status_t readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs, const bool isSysfs=false);
+    status_t readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
+                                       const bool isSysfs = false);
 
     /**
      * Whether we timed out.
@@ -90,4 +91,4 @@
     bool mTruncated;
 };
 
-#endif // FD_BUFFER_H
+#endif  // FD_BUFFER_H
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index 654036e..9ae6240 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -13,15 +13,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
 
 #include "IncidentService.h"
 
+#include "FdBuffer.h"
+#include "PrivacyBuffer.h"
 #include "Reporter.h"
+#include "incidentd_util.h"
+#include "section_list.h"
 
 #include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
 #include <binder/IServiceManager.h>
+#include <binder/IShellCallback.h>
 #include <cutils/log.h>
 #include <private/android_filesystem_config.h>
 #include <utils/Looper.h>
@@ -29,11 +34,9 @@
 #include <unistd.h>
 
 using namespace android;
+using namespace android::base;
 
-enum {
-    WHAT_RUN_REPORT = 1,
-    WHAT_SEND_BACKLOG_TO_DROPBOX = 2
-};
+enum { WHAT_RUN_REPORT = 1, WHAT_SEND_BACKLOG_TO_DROPBOX = 2 };
 
 //#define DEFAULT_BACKLOG_DELAY_NS (1000000000LL * 60 * 5)
 #define DEFAULT_BACKLOG_DELAY_NS (1000000000LL)
@@ -42,9 +45,7 @@
 String16 const DUMP_PERMISSION("android.permission.DUMP");
 String16 const USAGE_STATS_PERMISSION("android.permission.PACKAGE_USAGE_STATS");
 
-static Status
-checkIncidentPermissions(const IncidentReportArgs& args)
-{
+static Status checkIncidentPermissions(const IncidentReportArgs& args) {
     uid_t callingUid = IPCThreadState::self()->getCallingUid();
     pid_t callingPid = IPCThreadState::self()->getCallingPid();
     if (callingUid == AID_ROOT || callingUid == AID_SHELL) {
@@ -55,14 +56,16 @@
     // checking calling permission.
     if (!checkCallingPermission(DUMP_PERMISSION)) {
         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.DUMP",
-                callingPid, callingUid);
-        return Status::fromExceptionCode(Status::EX_SECURITY,
+              callingPid, callingUid);
+        return Status::fromExceptionCode(
+                Status::EX_SECURITY,
                 "Calling process does not have permission: android.permission.DUMP");
     }
     if (!checkCallingPermission(USAGE_STATS_PERMISSION)) {
         ALOGW("Calling pid %d and uid %d does not have permission: android.permission.USAGE_STATS",
-                callingPid, callingUid);
-        return Status::fromExceptionCode(Status::EX_SECURITY,
+              callingPid, callingUid);
+        return Status::fromExceptionCode(
+                Status::EX_SECURITY,
                 "Calling process does not have permission: android.permission.USAGE_STATS");
     }
 
@@ -71,40 +74,34 @@
         case DEST_LOCAL:
             if (callingUid != AID_SHELL && callingUid != AID_ROOT) {
                 ALOGW("Calling pid %d and uid %d does not have permission to get local data.",
-                        callingPid, callingUid);
-                return Status::fromExceptionCode(Status::EX_SECURITY,
-                    "Calling process does not have permission to get local data.");
+                      callingPid, callingUid);
+                return Status::fromExceptionCode(
+                        Status::EX_SECURITY,
+                        "Calling process does not have permission to get local data.");
             }
         case DEST_EXPLICIT:
-            if (callingUid != AID_SHELL && callingUid != AID_ROOT &&
-                callingUid != AID_STATSD && callingUid != AID_SYSTEM) {
+            if (callingUid != AID_SHELL && callingUid != AID_ROOT && callingUid != AID_STATSD &&
+                callingUid != AID_SYSTEM) {
                 ALOGW("Calling pid %d and uid %d does not have permission to get explicit data.",
-                        callingPid, callingUid);
-                return Status::fromExceptionCode(Status::EX_SECURITY,
-                    "Calling process does not have permission to get explicit data.");
+                      callingPid, callingUid);
+                return Status::fromExceptionCode(
+                        Status::EX_SECURITY,
+                        "Calling process does not have permission to get explicit data.");
             }
     }
     return Status::ok();
 }
 // ================================================================================
-ReportRequestQueue::ReportRequestQueue()
-{
-}
+ReportRequestQueue::ReportRequestQueue() {}
 
-ReportRequestQueue::~ReportRequestQueue()
-{
-}
+ReportRequestQueue::~ReportRequestQueue() {}
 
-void
-ReportRequestQueue::addRequest(const sp<ReportRequest>& request)
-{
+void ReportRequestQueue::addRequest(const sp<ReportRequest>& request) {
     unique_lock<mutex> lock(mLock);
     mQueue.push_back(request);
 }
 
-sp<ReportRequest>
-ReportRequestQueue::getNextRequest()
-{
+sp<ReportRequest> ReportRequestQueue::getNextRequest() {
     unique_lock<mutex> lock(mLock);
     if (mQueue.empty()) {
         return NULL;
@@ -115,22 +112,13 @@
     }
 }
 
-
 // ================================================================================
 ReportHandler::ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue)
-    :mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS),
-     mHandlerLooper(handlerLooper),
-     mQueue(queue)
-{
-}
+    : mBacklogDelay(DEFAULT_BACKLOG_DELAY_NS), mHandlerLooper(handlerLooper), mQueue(queue) {}
 
-ReportHandler::~ReportHandler()
-{
-}
+ReportHandler::~ReportHandler() {}
 
-void
-ReportHandler::handleMessage(const Message& message)
-{
+void ReportHandler::handleMessage(const Message& message) {
     switch (message.what) {
         case WHAT_RUN_REPORT:
             run_report();
@@ -141,33 +129,24 @@
     }
 }
 
-void
-ReportHandler::scheduleRunReport(const sp<ReportRequest>& request)
-{
+void ReportHandler::scheduleRunReport(const sp<ReportRequest>& request) {
     mQueue->addRequest(request);
     mHandlerLooper->removeMessages(this, WHAT_RUN_REPORT);
     mHandlerLooper->sendMessage(this, Message(WHAT_RUN_REPORT));
 }
 
-void
-ReportHandler::scheduleSendBacklogToDropbox()
-{
+void ReportHandler::scheduleSendBacklogToDropbox() {
     unique_lock<mutex> lock(mLock);
     mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
     schedule_send_backlog_to_dropbox_locked();
 }
 
-void
-ReportHandler::schedule_send_backlog_to_dropbox_locked()
-{
+void ReportHandler::schedule_send_backlog_to_dropbox_locked() {
     mHandlerLooper->removeMessages(this, WHAT_SEND_BACKLOG_TO_DROPBOX);
-    mHandlerLooper->sendMessageDelayed(mBacklogDelay, this,
-            Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
+    mHandlerLooper->sendMessageDelayed(mBacklogDelay, this, Message(WHAT_SEND_BACKLOG_TO_DROPBOX));
 }
 
-void
-ReportHandler::run_report()
-{
+void ReportHandler::run_report() {
     sp<Reporter> reporter = new Reporter();
 
     // Merge all of the requests into one that has all of the
@@ -190,15 +169,13 @@
     }
 }
 
-void
-ReportHandler::send_backlog_to_dropbox()
-{
+void ReportHandler::send_backlog_to_dropbox() {
     if (Reporter::upload_backlog() == Reporter::REPORT_NEEDS_DROPBOX) {
         // There was a failure. Exponential backoff.
         unique_lock<mutex> lock(mLock);
         mBacklogDelay *= 2;
         ALOGI("Error sending to dropbox. Trying again in %lld minutes",
-                (mBacklogDelay / (1000000000LL * 60)));
+              (mBacklogDelay / (1000000000LL * 60)));
         schedule_send_backlog_to_dropbox_locked();
     } else {
         mBacklogDelay = DEFAULT_BACKLOG_DELAY_NS;
@@ -207,18 +184,13 @@
 
 // ================================================================================
 IncidentService::IncidentService(const sp<Looper>& handlerLooper)
-    :mQueue(new ReportRequestQueue())
-{
+    : mQueue(new ReportRequestQueue()) {
     mHandler = new ReportHandler(handlerLooper, mQueue);
 }
 
-IncidentService::~IncidentService()
-{
-}
+IncidentService::~IncidentService() {}
 
-Status
-IncidentService::reportIncident(const IncidentReportArgs& args)
-{
+Status IncidentService::reportIncident(const IncidentReportArgs& args) {
     ALOGI("reportIncident");
 
     Status status = checkIncidentPermissions(args);
@@ -231,10 +203,9 @@
     return Status::ok();
 }
 
-Status
-IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
-            const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream)
-{
+Status IncidentService::reportIncidentToStream(const IncidentReportArgs& args,
+                                               const sp<IIncidentReportStatusListener>& listener,
+                                               const unique_fd& stream) {
     ALOGI("reportIncidentToStream");
 
     Status status = checkIncidentPermissions(args);
@@ -252,12 +223,10 @@
     return Status::ok();
 }
 
-Status
-IncidentService::systemRunning()
-{
+Status IncidentService::systemRunning() {
     if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
         return Status::fromExceptionCode(Status::EX_SECURITY,
-                "Only system uid can call systemRunning");
+                                         "Only system uid can call systemRunning");
     }
 
     // When system_server is up and running, schedule the dropbox task to run.
@@ -266,3 +235,120 @@
     return Status::ok();
 }
 
+/**
+ * Implement our own because the default binder implementation isn't
+ * properly handling SHELL_COMMAND_TRANSACTION.
+ */
+status_t IncidentService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                     uint32_t flags) {
+    status_t err;
+
+    switch (code) {
+        case SHELL_COMMAND_TRANSACTION: {
+            int in = data.readFileDescriptor();
+            int out = data.readFileDescriptor();
+            int err = data.readFileDescriptor();
+            int argc = data.readInt32();
+            Vector<String8> args;
+            for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+                args.add(String8(data.readString16()));
+            }
+            sp<IShellCallback> shellCallback = IShellCallback::asInterface(data.readStrongBinder());
+            sp<IResultReceiver> resultReceiver =
+                    IResultReceiver::asInterface(data.readStrongBinder());
+
+            FILE* fin = fdopen(in, "r");
+            FILE* fout = fdopen(out, "w");
+            FILE* ferr = fdopen(err, "w");
+
+            if (fin == NULL || fout == NULL || ferr == NULL) {
+                resultReceiver->send(NO_MEMORY);
+            } else {
+                err = command(fin, fout, ferr, args);
+                resultReceiver->send(err);
+            }
+
+            if (fin != NULL) {
+                fflush(fin);
+                fclose(fin);
+            }
+            if (fout != NULL) {
+                fflush(fout);
+                fclose(fout);
+            }
+            if (fout != NULL) {
+                fflush(ferr);
+                fclose(ferr);
+            }
+
+            return NO_ERROR;
+        }
+        default: { return BnIncidentManager::onTransact(code, data, reply, flags); }
+    }
+}
+
+status_t IncidentService::command(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+    const int argCount = args.size();
+
+    if (argCount >= 1) {
+        if (!args[0].compare(String8("privacy"))) {
+            return cmd_privacy(in, out, err, args);
+        }
+    }
+    return cmd_help(out);
+}
+
+status_t IncidentService::cmd_help(FILE* out) {
+    fprintf(out, "usage: adb shell cmd incident privacy print <section_id>\n");
+    fprintf(out, "usage: adb shell cmd incident privacy parse <section_id> < proto.txt\n");
+    fprintf(out, "    Prints/parses for the section id.\n");
+    return NO_ERROR;
+}
+
+static void printPrivacy(const Privacy* p, FILE* out, String8 indent) {
+    if (p == NULL) return;
+    fprintf(out, "%sid:%d, type:%d, dest:%d\n", indent.string(), p->field_id, p->type, p->dest);
+    if (p->children == NULL) return;
+    for (int i = 0; p->children[i] != NULL; i++) {  // NULL-terminated.
+        printPrivacy(p->children[i], out, indent + "  ");
+    }
+}
+
+status_t IncidentService::cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
+    const int argCount = args.size();
+    if (argCount >= 3) {
+        String8 opt = args[1];
+        int sectionId = atoi(args[2].string());
+
+        const Privacy* p = get_privacy_of_section(sectionId);
+        if (p == NULL) {
+            fprintf(err, "Can't find section id %d\n", sectionId);
+            return NO_ERROR;
+        }
+        fprintf(err, "Get privacy for %d\n", sectionId);
+        if (opt == "print") {
+            printPrivacy(p, out, String8(""));
+        } else if (opt == "parse") {
+            FdBuffer buf;
+            status_t error = buf.read(fileno(in), 60000);
+            if (error != NO_ERROR) {
+                fprintf(err, "Error reading from stdin\n");
+                return error;
+            }
+            fprintf(err, "Read %zu bytes\n", buf.size());
+            auto data = buf.data();
+            PrivacyBuffer pBuf(p, data);
+
+            PrivacySpec spec = PrivacySpec::new_spec(argCount > 3 ? atoi(args[3]) : -1);
+            error = pBuf.strip(spec);
+            if (error != NO_ERROR) {
+                fprintf(err, "Error strip pii fields with spec %d\n", spec.dest);
+                return error;
+            }
+            return pBuf.flush(fileno(out));
+        }
+    } else {
+        return cmd_help(out);
+    }
+    return NO_ERROR;
+}
diff --git a/cmds/incidentd/src/IncidentService.h b/cmds/incidentd/src/IncidentService.h
index d6f33df..3c66507 100644
--- a/cmds/incidentd/src/IncidentService.h
+++ b/cmds/incidentd/src/IncidentService.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef INCIDENT_SERVICE_H
 #define INCIDENT_SERVICE_H
@@ -32,8 +33,7 @@
 using namespace std;
 
 // ================================================================================
-class ReportRequestQueue : public virtual RefBase
-{
+class ReportRequestQueue : public virtual RefBase {
 public:
     ReportRequestQueue();
     virtual ~ReportRequestQueue();
@@ -46,10 +46,8 @@
     deque<sp<ReportRequest> > mQueue;
 };
 
-
 // ================================================================================
-class ReportHandler : public MessageHandler
-{
+class ReportHandler : public MessageHandler {
 public:
     ReportHandler(const sp<Looper>& handlerLooper, const sp<ReportRequestQueue>& queue);
     virtual ~ReportHandler();
@@ -89,7 +87,6 @@
     void send_backlog_to_dropbox();
 };
 
-
 // ================================================================================
 class IncidentService : public BnIncidentManager {
 public:
@@ -99,14 +96,29 @@
     virtual Status reportIncident(const IncidentReportArgs& args);
 
     virtual Status reportIncidentToStream(const IncidentReportArgs& args,
-            const sp<IIncidentReportStatusListener>& listener, const unique_fd& stream);
+                                          const sp<IIncidentReportStatusListener>& listener,
+                                          const unique_fd& stream);
 
     virtual Status systemRunning();
 
+    // Implement commands for debugging purpose.
+    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                                uint32_t flags) override;
+    virtual status_t command(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
+
 private:
     sp<ReportRequestQueue> mQueue;
     sp<ReportHandler> mHandler;
+
+    /**
+     * Commands print out help.
+     */
+    status_t cmd_help(FILE* out);
+
+    /**
+     * Commands related to privacy filtering.
+     */
+    status_t cmd_privacy(FILE* in, FILE* out, FILE* err, Vector<String8>& args);
 };
 
-
-#endif // INCIDENT_SERVICE_H
+#endif  // INCIDENT_SERVICE_H
diff --git a/cmds/incidentd/src/Log.h b/cmds/incidentd/src/Log.h
new file mode 100644
index 0000000..46efbd1
--- /dev/null
+++ b/cmds/incidentd/src/Log.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/*
+ * This file must be included at the top of the file. Other header files
+ * occasionally include log.h, and if LOG_TAG isn't set when that happens
+ * we'll get a preprocesser error when we try to define it here.
+ */
+
+#pragma once
+
+#define LOG_TAG "incidentd"
+#define DEBUG false
+
+#include <log/log.h>
+
+// Use the local value to turn on/off debug logs instead of using log.tag.properties.
+// The advantage is that in production compiler can remove the logging code if the local
+// DEBUG/VERBOSE is false.
+#define VLOG(...) \
+    if (DEBUG) ALOGD(__VA_ARGS__);
\ No newline at end of file
diff --git a/cmds/incidentd/src/Privacy.cpp b/cmds/incidentd/src/Privacy.cpp
index c5078f0..c42a87b 100644
--- a/cmds/incidentd/src/Privacy.cpp
+++ b/cmds/incidentd/src/Privacy.cpp
@@ -21,10 +21,9 @@
 
 uint64_t encode_field_id(const Privacy* p) { return (uint64_t)p->type << 32 | p->field_id; }
 
-const Privacy* lookup(const Privacy* p, uint32_t fieldId)
-{
+const Privacy* lookup(const Privacy* p, uint32_t fieldId) {
     if (p->children == NULL) return NULL;
-    for (int i=0; p->children[i] != NULL; i++) { // NULL-terminated.
+    for (int i = 0; p->children[i] != NULL; i++) {  // NULL-terminated.
         if (p->children[i]->field_id == fieldId) return p->children[i];
         // Incident section gen tool guarantees field ids in ascending order.
         if (p->children[i]->field_id > fieldId) return NULL;
@@ -32,41 +31,31 @@
     return NULL;
 }
 
-static bool allowDest(const uint8_t dest, const uint8_t policy)
-{
+static bool allowDest(const uint8_t dest, const uint8_t policy) {
     switch (policy) {
-    case android::os::DEST_LOCAL:
-        return dest == android::os::DEST_LOCAL;
-    case android::os::DEST_EXPLICIT:
-    case DEST_UNSET:
-        return dest == android::os::DEST_LOCAL ||
-            dest == android::os::DEST_EXPLICIT ||
-            dest == DEST_UNSET;
-    case android::os::DEST_AUTOMATIC:
-        return true;
-    default:
-        return false;
+        case android::os::DEST_LOCAL:
+            return dest == android::os::DEST_LOCAL;
+        case android::os::DEST_EXPLICIT:
+        case DEST_UNSET:
+            return dest == android::os::DEST_LOCAL || dest == android::os::DEST_EXPLICIT ||
+                   dest == DEST_UNSET;
+        case android::os::DEST_AUTOMATIC:
+            return true;
+        default:
+            return false;
     }
 }
 
-bool
-PrivacySpec::operator<(const PrivacySpec& other) const
-{
-  return dest < other.dest;
-}
+bool PrivacySpec::operator<(const PrivacySpec& other) const { return dest < other.dest; }
 
-bool
-PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const
-{
+bool PrivacySpec::CheckPremission(const Privacy* privacy, const uint8_t defaultDest) const {
     uint8_t policy = privacy != NULL ? privacy->dest : defaultDest;
     return allowDest(dest, policy);
 }
 
-bool
-PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }
+bool PrivacySpec::RequireAll() const { return dest == android::os::DEST_LOCAL; }
 
-PrivacySpec PrivacySpec::new_spec(int dest)
-{
+PrivacySpec PrivacySpec::new_spec(int dest) {
     switch (dest) {
         case android::os::DEST_AUTOMATIC:
         case android::os::DEST_EXPLICIT:
diff --git a/cmds/incidentd/src/Privacy.h b/cmds/incidentd/src/Privacy.h
index ce1b8e9..6b6de9c 100644
--- a/cmds/incidentd/src/Privacy.h
+++ b/cmds/incidentd/src/Privacy.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef PRIVACY_H
 #define PRIVACY_H
@@ -20,7 +21,7 @@
 #include <stdint.h>
 
 // This is the default value of DEST enum, sync with privacy.proto
-const uint8_t DEST_UNSET = 255; // DEST_UNSET is not exposed to libincident
+const uint8_t DEST_UNSET = 255;  // DEST_UNSET is not exposed to libincident
 const uint8_t DEST_DEFAULT_VALUE = DEST_UNSET;
 
 /*
@@ -68,15 +69,17 @@
     bool operator<(const PrivacySpec& other) const;
 
     // check permission of a policy, if returns true, don't strip the data.
-    bool CheckPremission(const Privacy* privacy, const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;
+    bool CheckPremission(const Privacy* privacy,
+                         const uint8_t defaultDest = DEST_DEFAULT_VALUE) const;
 
     // if returns true, no data need to be stripped.
     bool RequireAll() const;
 
     // Constructs spec using static methods below.
     static PrivacySpec new_spec(int dest);
+
 private:
     PrivacySpec(uint8_t dest) : dest(dest) {}
 };
 
-#endif // PRIVACY_H
+#endif  // PRIVACY_H
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index f53befe..e4128f4 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -13,29 +13,22 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
 
 #include "PrivacyBuffer.h"
-#include "io_util.h"
+#include "incidentd_util.h"
 
+#include <android-base/file.h>
 #include <android/util/protobuf.h>
 #include <cutils/log.h>
 
 using namespace android::util;
 
-const bool DEBUG = false;
-
 /**
  * Write the field to buf based on the wire type, iterator will point to next field.
  * If skip is set to true, no data will be written to buf. Return number of bytes written.
  */
-void
-PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip)
-{
-    if (DEBUG) ALOGD("%s field %d (wiretype = %d)", skip ? "skip" : "write",
-        read_field_id(fieldTag), read_wire_type(fieldTag));
-
+void PrivacyBuffer::writeFieldOrSkip(uint32_t fieldTag, bool skip) {
     uint8_t wireType = read_wire_type(fieldTag);
     size_t bytesToWrite = 0;
     uint32_t varint = 0;
@@ -54,18 +47,17 @@
             break;
         case WIRE_TYPE_LENGTH_DELIMITED:
             bytesToWrite = mData.readRawVarint();
-            if(!skip) mProto.writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
+            if (!skip) mProto.writeLengthDelimitedHeader(read_field_id(fieldTag), bytesToWrite);
             break;
         case WIRE_TYPE_FIXED32:
             if (!skip) mProto.writeRawVarint(fieldTag);
             bytesToWrite = 4;
             break;
     }
-    if (DEBUG) ALOGD("%s %d bytes of data", skip ? "skip" : "write", (int)bytesToWrite);
     if (skip) {
         mData.rp()->move(bytesToWrite);
     } else {
-        for (size_t i=0; i<bytesToWrite; i++) {
+        for (size_t i = 0; i < bytesToWrite; i++) {
             mProto.writeRawByte(mData.next());
         }
     }
@@ -78,28 +70,29 @@
  * The iterator must point to the head of a protobuf formatted field for successful operation.
  * After exit with NO_ERROR, iterator points to the next protobuf field's head.
  */
-status_t
-PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec)
-{
+status_t PrivacyBuffer::stripField(const Privacy* parentPolicy, const PrivacySpec& spec,
+                                   int depth /* use as a counter for this recusive method. */) {
     if (!mData.hasNext() || parentPolicy == NULL) return BAD_VALUE;
     uint32_t fieldTag = mData.readRawVarint();
-    const Privacy* policy = lookup(parentPolicy, read_field_id(fieldTag));
+    uint32_t fieldId = read_field_id(fieldTag);
+    const Privacy* policy = lookup(parentPolicy, fieldId);
 
+    VLOG("[Depth %2d]Try to strip id %d, wiretype %d", depth, fieldId, read_wire_type(fieldTag));
     if (policy == NULL || policy->children == NULL) {
-        if (DEBUG) ALOGD("Not a message field %d: dest(%d)", read_field_id(fieldTag),
-            policy != NULL ? policy->dest : parentPolicy->dest);
-
         bool skip = !spec.CheckPremission(policy, parentPolicy->dest);
         // iterator will point to head of next field
+        size_t currentAt = mData.rp()->pos();
         writeFieldOrSkip(fieldTag, skip);
+        VLOG("[Depth %2d]Field %d %ss %d bytes", depth, fieldId, skip ? "skip" : "write",
+             (int)(get_varint_size(fieldTag) + mData.rp()->pos() - currentAt));
         return NO_ERROR;
     }
     // current field is message type and its sub-fields have extra privacy policies
     uint32_t msgSize = mData.readRawVarint();
-    EncodedBuffer::Pointer start = mData.rp()->copy();
+    size_t start = mData.rp()->pos();
     long long token = mProto.start(encode_field_id(policy));
-    while (mData.rp()->pos() - start.pos() != msgSize) {
-        status_t err = stripField(policy, spec);
+    while (mData.rp()->pos() - start != msgSize) {
+        status_t err = stripField(policy, spec, depth + 1);
         if (err != NO_ERROR) return err;
     }
     mProto.end(token);
@@ -108,53 +101,39 @@
 
 // ================================================================================
 PrivacyBuffer::PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data)
-        :mPolicy(policy),
-         mData(data),
-         mProto(),
-         mSize(0)
-{
-}
+    : mPolicy(policy), mData(data), mProto(), mSize(0) {}
 
-PrivacyBuffer::~PrivacyBuffer()
-{
-}
+PrivacyBuffer::~PrivacyBuffer() {}
 
-status_t
-PrivacyBuffer::strip(const PrivacySpec& spec)
-{
-    if (DEBUG) ALOGD("Strip with spec %d", spec.dest);
+status_t PrivacyBuffer::strip(const PrivacySpec& spec) {
+    VLOG("Strip with spec %d", spec.dest);
     // optimization when no strip happens
     if (mPolicy == NULL || mPolicy->children == NULL || spec.RequireAll()) {
         if (spec.CheckPremission(mPolicy)) mSize = mData.size();
         return NO_ERROR;
     }
     while (mData.hasNext()) {
-        status_t err = stripField(mPolicy, spec);
+        status_t err = stripField(mPolicy, spec, 0);
         if (err != NO_ERROR) return err;
     }
     if (mData.bytesRead() != mData.size()) return BAD_VALUE;
     mSize = mProto.size();
-    mData.rp()->rewind(); // rewind the read pointer back to beginning after the strip.
+    mData.rp()->rewind();  // rewind the read pointer back to beginning after the strip.
     return NO_ERROR;
 }
 
-void
-PrivacyBuffer::clear()
-{
+void PrivacyBuffer::clear() {
     mSize = 0;
     mProto.clear();
 }
 
-size_t
-PrivacyBuffer::size() const { return mSize; }
+size_t PrivacyBuffer::size() const { return mSize; }
 
-status_t
-PrivacyBuffer::flush(int fd)
-{
+status_t PrivacyBuffer::flush(int fd) {
     status_t err = NO_ERROR;
     EncodedBuffer::iterator iter = size() == mData.size() ? mData : mProto.data();
     while (iter.readBuffer() != NULL) {
-        err = write_all(fd, iter.readBuffer(), iter.currentToRead());
+        err = WriteFully(fd, iter.readBuffer(), iter.currentToRead()) ? NO_ERROR : -errno;
         iter.rp()->move(iter.currentToRead());
         if (err != NO_ERROR) return err;
     }
diff --git a/cmds/incidentd/src/PrivacyBuffer.h b/cmds/incidentd/src/PrivacyBuffer.h
index c9ca9a7..92e1a25 100644
--- a/cmds/incidentd/src/PrivacyBuffer.h
+++ b/cmds/incidentd/src/PrivacyBuffer.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef PRIVACY_BUFFER_H
 #define PRIVACY_BUFFER_H
@@ -31,14 +32,14 @@
  * PrivacyBuffer holds the original protobuf data and strips PII-sensitive fields
  * based on the request and holds stripped data in its own buffer for output.
  */
-class PrivacyBuffer
-{
+class PrivacyBuffer {
 public:
     PrivacyBuffer(const Privacy* policy, EncodedBuffer::iterator& data);
     ~PrivacyBuffer();
 
     /**
-     * Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip succeeds.
+     * Strip based on the request and hold data in its own buffer. Return NO_ERROR if strip
+     * succeeds.
      */
     status_t strip(const PrivacySpec& spec);
 
@@ -64,8 +65,8 @@
     ProtoOutputStream mProto;
     size_t mSize;
 
-    status_t stripField(const Privacy* parentPolicy, const PrivacySpec& spec);
+    status_t stripField(const Privacy* parentPolicy, const PrivacySpec& spec, int depth);
     void writeFieldOrSkip(uint32_t fieldTag, bool skip);
 };
 
-#endif // PRIVACY_BUFFER_H
\ No newline at end of file
+#endif  // PRIVACY_BUFFER_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 06baeba..c0b5358 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
 
 #include "Reporter.h"
 
@@ -26,11 +25,11 @@
 #include <private/android_filesystem_config.h>
 #include <utils/SystemClock.h>
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <dirent.h>
-#include <fcntl.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 /**
  * The directory where the incident reports are stored.
@@ -39,62 +38,37 @@
 
 // ================================================================================
 ReportRequest::ReportRequest(const IncidentReportArgs& a,
-            const sp<IIncidentReportStatusListener> &l, int f)
-    :args(a),
-     listener(l),
-     fd(f),
-     err(NO_ERROR)
-{
-}
+                             const sp<IIncidentReportStatusListener>& l, int f)
+    : args(a), listener(l), fd(f), err(NO_ERROR) {}
 
-ReportRequest::~ReportRequest()
-{
+ReportRequest::~ReportRequest() {
     if (fd >= 0) {
         // clean up the opened file descriptor
         close(fd);
     }
 }
 
-bool
-ReportRequest::ok()
-{
-    return fd >= 0 && err == NO_ERROR;
-}
+bool ReportRequest::ok() { return fd >= 0 && err == NO_ERROR; }
 
 // ================================================================================
 ReportRequestSet::ReportRequestSet()
-    :mRequests(),
-     mSections(),
-     mMainFd(-1),
-     mMainDest(-1),
-     mMetadata(),
-     mSectionStats()
-{
-}
+    : mRequests(), mSections(), mMainFd(-1), mMainDest(-1), mMetadata(), mSectionStats() {}
 
-ReportRequestSet::~ReportRequestSet()
-{
-}
+ReportRequestSet::~ReportRequestSet() {}
 
 // TODO: dedup on exact same args and fd, report the status back to listener!
-void
-ReportRequestSet::add(const sp<ReportRequest>& request)
-{
+void ReportRequestSet::add(const sp<ReportRequest>& request) {
     mRequests.push_back(request);
     mSections.merge(request->args);
     mMetadata.set_request_size(mMetadata.request_size() + 1);
 }
 
-void
-ReportRequestSet::setMainFd(int fd)
-{
+void ReportRequestSet::setMainFd(int fd) {
     mMainFd = fd;
     mMetadata.set_use_dropbox(fd > 0);
 }
 
-void
-ReportRequestSet::setMainDest(int dest)
-{
+void ReportRequestSet::setMainDest(int dest) {
     mMainDest = dest;
     PrivacySpec spec = PrivacySpec::new_spec(dest);
     switch (spec.dest) {
@@ -110,13 +84,9 @@
     }
 }
 
-bool
-ReportRequestSet::containsSection(int id) {
-    return mSections.containsSection(id);
-}
+bool ReportRequestSet::containsSection(int id) { return mSections.containsSection(id); }
 
-IncidentMetadata::SectionStats*
-ReportRequestSet::sectionStats(int id) {
+IncidentMetadata::SectionStats* ReportRequestSet::sectionStats(int id) {
     if (mSectionStats.find(id) == mSectionStats.end()) {
         auto stats = mMetadata.add_sections();
         stats->set_id(id);
@@ -128,9 +98,7 @@
 // ================================================================================
 Reporter::Reporter() : Reporter(INCIDENT_DIRECTORY) { isTest = false; };
 
-Reporter::Reporter(const char* directory)
-    :batch()
-{
+Reporter::Reporter(const char* directory) : batch() {
     char buf[100];
 
     // TODO: Make the max size smaller for user builds.
@@ -148,13 +116,9 @@
     mFilename = mIncidentDirectory + buf;
 }
 
-Reporter::~Reporter()
-{
-}
+Reporter::~Reporter() {}
 
-Reporter::run_report_status_t
-Reporter::runReport()
-{
+Reporter::run_report_status_t Reporter::runReport() {
     status_t err = NO_ERROR;
     bool needMainFd = false;
     int mainFd = -1;
@@ -163,7 +127,7 @@
     MetadataSection metadataSection;
 
     // See if we need the main file
-    for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+    for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
         if ((*it)->fd < 0 && mainFd < 0) {
             needMainFd = true;
             mainDest = (*it)->args.dest();
@@ -194,7 +158,7 @@
     }
 
     // Tell everyone that we're starting.
-    for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+    for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
         if ((*it)->listener != NULL) {
             (*it)->listener->onReportStarted();
         }
@@ -205,15 +169,14 @@
 
     // For each of the report fields, see if we need it, and if so, execute the command
     // and report to those that care that we're doing it.
-    for (const Section** section=SECTION_LIST; *section; section++) {
+    for (const Section** section = SECTION_LIST; *section; section++) {
         const int id = (*section)->id;
         if (this->batch.containsSection(id)) {
             ALOGD("Taking incident report section %d '%s'", id, (*section)->name.string());
-            // Notify listener of starting.
-            for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+            for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
                 if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
-                    (*it)->listener->onReportSectionStatus(id,
-                            IIncidentReportStatusListener::STATUS_STARTING);
+                    (*it)->listener->onReportSectionStatus(
+                            id, IIncidentReportStatusListener::STATUS_STARTING);
                 }
             }
 
@@ -227,15 +190,15 @@
             stats->set_exec_duration_ms(endTime - startTime);
             if (err != NO_ERROR) {
                 ALOGW("Incident section %s (%d) failed: %s. Stopping report.",
-                        (*section)->name.string(), id, strerror(-err));
+                      (*section)->name.string(), id, strerror(-err));
                 goto DONE;
             }
 
-            // Notify listener of ending.
-            for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+            // Notify listener of starting
+            for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
                 if ((*it)->listener != NULL && (*it)->args.containsSection(id)) {
-                    (*it)->listener->onReportSectionStatus(id,
-                            IIncidentReportStatusListener::STATUS_FINISHED);
+                    (*it)->listener->onReportSectionStatus(
+                            id, IIncidentReportStatusListener::STATUS_FINISHED);
                 }
             }
             ALOGD("Finish incident report section %d '%s'", id, (*section)->name.string());
@@ -252,7 +215,7 @@
     }
 
     // Tell everyone that we're done.
-    for (ReportRequestSet::iterator it=batch.begin(); it!=batch.end(); it++) {
+    for (ReportRequestSet::iterator it = batch.begin(); it != batch.end(); it++) {
         if ((*it)->listener != NULL) {
             if (err == NO_ERROR) {
                 (*it)->listener->onReportFinished();
@@ -274,7 +237,7 @@
         // If the status was ok, delete the file. If not, leave it around until the next
         // boot or the next checkin. If the directory gets too big older files will
         // be rotated out.
-        if(!isTest) unlink(mFilename.c_str());
+        if (!isTest) unlink(mFilename.c_str());
     }
 
     return REPORT_FINISHED;
@@ -283,9 +246,7 @@
 /**
  * Create our output file and set the access permissions to -rw-rw----
  */
-status_t
-Reporter::create_file(int* fd)
-{
+status_t Reporter::create_file(int* fd) {
     const char* filename = mFilename.c_str();
 
     *fd = open(filename, O_CREAT | O_TRUNC | O_RDWR | O_CLOEXEC, 0660);
@@ -307,9 +268,7 @@
     return NO_ERROR;
 }
 
-Reporter::run_report_status_t
-Reporter::upload_backlog()
-{
+Reporter::run_report_status_t Reporter::upload_backlog() {
     DIR* dir;
     struct dirent* entry;
     struct stat st;
@@ -360,4 +319,3 @@
 
     return REPORT_FINISHED;
 }
-
diff --git a/cmds/incidentd/src/Reporter.h b/cmds/incidentd/src/Reporter.h
index 6058068..0f3f221 100644
--- a/cmds/incidentd/src/Reporter.h
+++ b/cmds/incidentd/src/Reporter.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef REPORTER_H
 #define REPORTER_H
@@ -33,23 +34,21 @@
 using namespace std;
 
 // ================================================================================
-struct ReportRequest : public virtual RefBase
-{
+struct ReportRequest : public virtual RefBase {
     IncidentReportArgs args;
     sp<IIncidentReportStatusListener> listener;
     int fd;
     status_t err;
 
-    ReportRequest(const IncidentReportArgs& args,
-            const sp<IIncidentReportStatusListener> &listener, int fd);
+    ReportRequest(const IncidentReportArgs& args, const sp<IIncidentReportStatusListener>& listener,
+                  int fd);
     virtual ~ReportRequest();
 
-    bool ok(); // returns true if the request is ok for write.
+    bool ok();  // returns true if the request is ok for write.
 };
 
 // ================================================================================
-class ReportRequestSet
-{
+class ReportRequestSet {
 public:
     ReportRequestSet();
     ~ReportRequestSet();
@@ -81,18 +80,14 @@
 };
 
 // ================================================================================
-class Reporter : public virtual RefBase
-{
+class Reporter : public virtual RefBase {
 public:
-    enum run_report_status_t {
-        REPORT_FINISHED = 0,
-        REPORT_NEEDS_DROPBOX = 1
-    };
+    enum run_report_status_t { REPORT_FINISHED = 0, REPORT_NEEDS_DROPBOX = 1 };
 
     ReportRequestSet batch;
 
-    Reporter(); // PROD must use this constructor.
-    Reporter(const char* directory); // For testing purpose only.
+    Reporter();                       // PROD must use this constructor.
+    Reporter(const char* directory);  // For testing purpose only.
     virtual ~Reporter();
 
     // Run the report as described in the batch and args parameters.
@@ -110,8 +105,7 @@
 
     status_t create_file(int* fd);
 
-    bool isTest = true; // default to true for testing
+    bool isTest = true;  // default to true for testing
 };
 
-
-#endif // REPORTER_H
+#endif  // REPORTER_H
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 3c76298..2e4e980 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
 
 #include "Section.h"
 
@@ -26,20 +25,21 @@
 #include <memory>
 #include <mutex>
 
+#include <android-base/file.h>
 #include <android/util/protobuf.h>
 #include <binder/IServiceManager.h>
 #include <log/log_event_list.h>
-#include <log/logprint.h>
 #include <log/log_read.h>
+#include <log/logprint.h>
 #include <private/android_logger.h>
 
 #include "FdBuffer.h"
-#include "frameworks/base/core/proto/android/util/log.proto.h"
-#include "io_util.h"
 #include "Privacy.h"
 #include "PrivacyBuffer.h"
-#include "section_list.h"
+#include "frameworks/base/core/proto/android/util/log.proto.h"
+#include "incidentd_util.h"
 
+using namespace android::base;
 using namespace android::util;
 using namespace std;
 
@@ -48,21 +48,18 @@
 const int FIELD_ID_INCIDENT_METADATA = 2;
 
 // incident section parameters
-const int   WAIT_MAX = 5;
+const int WAIT_MAX = 5;
 const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
 const char INCIDENT_HELPER[] = "/system/bin/incident_helper";
 
-static pid_t
-fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, Fpipe& c2pPipe)
-{
-    const char* ihArgs[] { INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL };
+static pid_t fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe,
+                                          Fpipe& c2pPipe) {
+    const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL};
     // fork used in multithreaded environment, avoid adding unnecessary code in child process
     pid_t pid = fork();
     if (pid == 0) {
-        if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(),  STDIN_FILENO))  != 0
-            || !p2cPipe.close()
-            || TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1
-            || !c2pPipe.close()) {
+        if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0 || !p2cPipe.close() ||
+            TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1 || !c2pPipe.close()) {
             ALOGW("%s can't setup stdin and stdout for incident helper", name);
             _exit(EXIT_FAILURE);
         }
@@ -73,7 +70,7 @@
         execv(INCIDENT_HELPER, const_cast<char**>(ihArgs));
 
         ALOGW("%s failed in incident helper process: %s", name, strerror(errno));
-        _exit(EXIT_FAILURE); // always exits with failure if any
+        _exit(EXIT_FAILURE);  // always exits with failure if any
     }
     // close the fds used in incident helper
     close(p2cPipe.readFd());
@@ -84,18 +81,18 @@
 // ================================================================================
 static status_t statusCode(int status) {
     if (WIFSIGNALED(status)) {
-      ALOGD("return by signal: %s", strerror(WTERMSIG(status)));
-      return -WTERMSIG(status);
+        VLOG("return by signal: %s", strerror(WTERMSIG(status)));
+        return -WTERMSIG(status);
     } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
-      ALOGD("return by exit: %s", strerror(WEXITSTATUS(status)));
-      return -WEXITSTATUS(status);
+        VLOG("return by exit: %s", strerror(WEXITSTATUS(status)));
+        return -WEXITSTATUS(status);
     }
     return NO_ERROR;
 }
 
 static status_t kill_child(pid_t pid) {
     int status;
-    ALOGD("try to kill child process %d", pid);
+    VLOG("try to kill child process %d", pid);
     kill(pid, SIGKILL);
     if (waitpid(pid, &status, 0) == -1) return -1;
     return statusCode(status);
@@ -105,7 +102,7 @@
     int status;
     bool died = false;
     // wait for child to report status up to 1 seconds
-    for(int loop = 0; !died && loop < WAIT_MAX; loop++) {
+    for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
         if (waitpid(pid, &status, WNOHANG) == pid) died = true;
         // sleep for 0.2 second
         nanosleep(&WAIT_INTERVAL_NS, NULL);
@@ -114,38 +111,14 @@
     return statusCode(status);
 }
 // ================================================================================
-static const Privacy*
-get_privacy_of_section(int id)
-{
-    int l = 0;
-    int r = PRIVACY_POLICY_COUNT - 1;
-    while (l <= r) {
-        int mid = (l + r) >> 1;
-        const Privacy* p = PRIVACY_POLICY_LIST[mid];
-
-        if (p->field_id < (uint32_t)id) {
-            l = mid + 1;
-        } else if (p->field_id > (uint32_t)id) {
-            r = mid - 1;
-        } else {
-            return p;
-        }
-    }
-    return NULL;
-}
-
-// ================================================================================
-static status_t
-write_section_header(int fd, int sectionId, size_t size)
-{
+static status_t write_section_header(int fd, int sectionId, size_t size) {
     uint8_t buf[20];
-    uint8_t *p = write_length_delimited_tag_header(buf, sectionId, size);
-    return write_all(fd, buf, p-buf);
+    uint8_t* p = write_length_delimited_tag_header(buf, sectionId, size);
+    return WriteFully(fd, buf, p - buf) ? NO_ERROR : -errno;
 }
 
-static status_t
-write_report_requests(const int id, const FdBuffer& buffer, ReportRequestSet* requests)
-{
+static status_t write_report_requests(const int id, const FdBuffer& buffer,
+                                      ReportRequestSet* requests) {
     status_t err = -EBADF;
     EncodedBuffer::iterator data = buffer.data();
     PrivacyBuffer privacyBuffer(get_privacy_of_section(id), data);
@@ -171,18 +144,24 @@
     for (auto mit = requestsBySpec.begin(); mit != requestsBySpec.end(); mit++) {
         PrivacySpec spec = mit->first;
         err = privacyBuffer.strip(spec);
-        if (err != NO_ERROR) return err; // it means the privacyBuffer data is corrupted.
+        if (err != NO_ERROR) return err;  // it means the privacyBuffer data is corrupted.
         if (privacyBuffer.size() == 0) continue;
 
         for (auto it = mit->second.begin(); it != mit->second.end(); it++) {
             sp<ReportRequest> request = *it;
             err = write_section_header(request->fd, id, privacyBuffer.size());
-            if (err != NO_ERROR) { request->err = err; continue; }
+            if (err != NO_ERROR) {
+                request->err = err;
+                continue;
+            }
             err = privacyBuffer.flush(request->fd);
-            if (err != NO_ERROR) { request->err = err; continue; }
+            if (err != NO_ERROR) {
+                request->err = err;
+                continue;
+            }
             writeable++;
-            ALOGD("Section %d flushed %zu bytes to fd %d with spec %d", id,
-                  privacyBuffer.size(), request->fd, spec.dest);
+            VLOG("Section %d flushed %zu bytes to fd %d with spec %d", id, privacyBuffer.size(),
+                 request->fd, spec.dest);
         }
         privacyBuffer.clear();
     }
@@ -191,16 +170,22 @@
     if (requests->mainFd() >= 0) {
         PrivacySpec spec = PrivacySpec::new_spec(requests->mainDest());
         err = privacyBuffer.strip(spec);
-        if (err != NO_ERROR) return err; // the buffer data is corrupted.
+        if (err != NO_ERROR) return err;  // the buffer data is corrupted.
         if (privacyBuffer.size() == 0) goto DONE;
 
         err = write_section_header(requests->mainFd(), id, privacyBuffer.size());
-        if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
+        if (err != NO_ERROR) {
+            requests->setMainFd(-1);
+            goto DONE;
+        }
         err = privacyBuffer.flush(requests->mainFd());
-        if (err != NO_ERROR) { requests->setMainFd(-1); goto DONE; }
+        if (err != NO_ERROR) {
+            requests->setMainFd(-1);
+            goto DONE;
+        }
         writeable++;
-        ALOGD("Section %d flushed %zu bytes to dropbox %d with spec %d", id,
-              privacyBuffer.size(), requests->mainFd(), spec.dest);
+        VLOG("Section %d flushed %zu bytes to dropbox %d with spec %d", id, privacyBuffer.size(),
+             requests->mainFd(), spec.dest);
         stats->set_report_size_bytes(privacyBuffer.size());
     }
 
@@ -210,40 +195,28 @@
 }
 
 // ================================================================================
-Section::Section(int i, const int64_t timeoutMs)
-    :id(i),
-     timeoutMs(timeoutMs)
-{
-}
+Section::Section(int i, const int64_t timeoutMs) : id(i), timeoutMs(timeoutMs) {}
 
-Section::~Section()
-{
-}
+Section::~Section() {}
 
 // ================================================================================
-HeaderSection::HeaderSection()
-    :Section(FIELD_ID_INCIDENT_HEADER, 0)
-{
-}
+HeaderSection::HeaderSection() : Section(FIELD_ID_INCIDENT_HEADER, 0) {}
 
-HeaderSection::~HeaderSection()
-{
-}
+HeaderSection::~HeaderSection() {}
 
-status_t
-HeaderSection::Execute(ReportRequestSet* requests) const
-{
-    for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
+status_t HeaderSection::Execute(ReportRequestSet* requests) const {
+    for (ReportRequestSet::iterator it = requests->begin(); it != requests->end(); it++) {
         const sp<ReportRequest> request = *it;
         const vector<vector<uint8_t>>& headers = request->args.headers();
 
-        for (vector<vector<uint8_t>>::const_iterator buf=headers.begin(); buf!=headers.end(); buf++) {
+        for (vector<vector<uint8_t>>::const_iterator buf = headers.begin(); buf != headers.end();
+             buf++) {
             if (buf->empty()) continue;
 
             // So the idea is only requests with negative fd are written to dropbox file.
             int fd = request->fd >= 0 ? request->fd : requests->mainFd();
             write_section_header(fd, id, buf->size());
-            write_all(fd, (uint8_t const*)buf->data(), buf->size());
+            WriteFully(fd, (uint8_t const*)buf->data(), buf->size());
             // If there was an error now, there will be an error later and we will remove
             // it from the list then.
         }
@@ -251,54 +224,49 @@
     return NO_ERROR;
 }
 // ================================================================================
-MetadataSection::MetadataSection()
-    :Section(FIELD_ID_INCIDENT_METADATA, 0)
-{
-}
+MetadataSection::MetadataSection() : Section(FIELD_ID_INCIDENT_METADATA, 0) {}
 
-MetadataSection::~MetadataSection()
-{
-}
+MetadataSection::~MetadataSection() {}
 
-status_t
-MetadataSection::Execute(ReportRequestSet* requests) const
-{
+status_t MetadataSection::Execute(ReportRequestSet* requests) const {
     std::string metadataBuf;
     requests->metadata().SerializeToString(&metadataBuf);
-    for (ReportRequestSet::iterator it=requests->begin(); it!=requests->end(); it++) {
+    for (ReportRequestSet::iterator it = requests->begin(); it != requests->end(); it++) {
         const sp<ReportRequest> request = *it;
         if (metadataBuf.empty() || request->fd < 0 || request->err != NO_ERROR) {
             continue;
         }
         write_section_header(request->fd, id, metadataBuf.size());
-        write_all(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+        if (!WriteFully(request->fd, (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+            ALOGW("Failed to write metadata to fd %d", request->fd);
+            // we don't fail if we can't write to a single request's fd.
+        }
     }
     if (requests->mainFd() >= 0 && !metadataBuf.empty()) {
         write_section_header(requests->mainFd(), id, metadataBuf.size());
-        write_all(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size());
+        if (!WriteFully(requests->mainFd(), (uint8_t const*)metadataBuf.data(), metadataBuf.size())) {
+            ALOGW("Failed to write metadata to dropbox fd %d", requests->mainFd());
+            return -1;
+        }
     }
     return NO_ERROR;
 }
 // ================================================================================
 FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
-    :Section(id, timeoutMs),
-     mFilename(filename)
-{
+    : Section(id, timeoutMs), mFilename(filename) {
     name = filename;
     mIsSysfs = strncmp(filename, "/sys/", 5) == 0;
 }
 
 FileSection::~FileSection() {}
 
-status_t
-FileSection::Execute(ReportRequestSet* requests) const
-{
+status_t FileSection::Execute(ReportRequestSet* requests) const {
     // read from mFilename first, make sure the file is available
     // add O_CLOEXEC to make sure it is closed when exec incident helper
     int fd = open(mFilename, O_RDONLY | O_CLOEXEC);
     if (fd == -1) {
-       ALOGW("FileSection '%s' failed to open file", this->name.string());
-       return -errno;
+        ALOGW("FileSection '%s' failed to open file", this->name.string());
+        return -errno;
     }
 
     FdBuffer buffer;
@@ -318,22 +286,23 @@
 
     // parent process
     status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(),
-            this->timeoutMs, mIsSysfs);
+                                                           this->timeoutMs, mIsSysfs);
     if (readStatus != NO_ERROR || buffer.timedOut()) {
         ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
-            this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+              this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
         kill_child(pid);
         return readStatus;
     }
 
     status_t ihStatus = wait_child(pid);
     if (ihStatus != NO_ERROR) {
-        ALOGW("FileSection '%s' abnormal child process: %s", this->name.string(), strerror(-ihStatus));
+        ALOGW("FileSection '%s' abnormal child process: %s", this->name.string(),
+              strerror(-ihStatus));
         return ihStatus;
     }
 
-    ALOGD("FileSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
-            (int)buffer.durationMs());
+    VLOG("FileSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
+         (int)buffer.durationMs());
     status_t err = write_report_requests(this->id, buffer, requests);
     if (err != NO_ERROR) {
         ALOGW("FileSection '%s' failed writing: %s", this->name.string(), strerror(-err));
@@ -344,8 +313,7 @@
 }
 
 // ================================================================================
-struct WorkerThreadData : public virtual RefBase
-{
+struct WorkerThreadData : public virtual RefBase {
     const WorkerThreadSection* section;
     int fds[2];
 
@@ -362,31 +330,19 @@
 };
 
 WorkerThreadData::WorkerThreadData(const WorkerThreadSection* sec)
-    :section(sec),
-     workerDone(false),
-     workerError(NO_ERROR)
-{
+    : section(sec), workerDone(false), workerError(NO_ERROR) {
     fds[0] = -1;
     fds[1] = -1;
 }
 
-WorkerThreadData::~WorkerThreadData()
-{
-}
+WorkerThreadData::~WorkerThreadData() {}
 
 // ================================================================================
-WorkerThreadSection::WorkerThreadSection(int id)
-    :Section(id)
-{
-}
+WorkerThreadSection::WorkerThreadSection(int id) : Section(id) {}
 
-WorkerThreadSection::~WorkerThreadSection()
-{
-}
+WorkerThreadSection::~WorkerThreadSection() {}
 
-static void*
-worker_thread_func(void* cookie)
-{
+static void* worker_thread_func(void* cookie) {
     WorkerThreadData* data = (WorkerThreadData*)cookie;
     status_t err = data->section->BlockingCall(data->writeFd());
 
@@ -402,9 +358,7 @@
     return NULL;
 }
 
-status_t
-WorkerThreadSection::Execute(ReportRequestSet* requests) const
-{
+status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const {
     status_t err = NO_ERROR;
     pthread_t thread;
     pthread_attr_t attr;
@@ -447,7 +401,7 @@
     if (err != NO_ERROR) {
         // TODO: Log this error into the incident report.
         ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(),
-                strerror(-err));
+              strerror(-err));
     }
 
     // Done with the read fd. The worker thread closes the write one so
@@ -466,7 +420,7 @@
                 err = data->workerError;
                 // TODO: Log this error into the incident report.
                 ALOGW("WorkerThreadSection '%s' worker failed with error '%s'", this->name.string(),
-                        strerror(-err));
+                      strerror(-err));
             }
         }
     }
@@ -484,13 +438,13 @@
     // just exit with a log messasge.
     if (err != NO_ERROR) {
         ALOGW("WorkerThreadSection '%s' failed with error '%s'", this->name.string(),
-                strerror(-err));
+              strerror(-err));
         return NO_ERROR;
     }
 
     // Write the data that was collected
-    ALOGD("WorkerThreadSection '%s' wrote %zd bytes in %d ms", name.string(), buffer.size(),
-            (int)buffer.durationMs());
+    VLOG("WorkerThreadSection '%s' wrote %zd bytes in %d ms", name.string(), buffer.size(),
+         (int)buffer.durationMs());
     err = write_report_requests(this->id, buffer, requests);
     if (err != NO_ERROR) {
         ALOGW("WorkerThreadSection '%s' failed writing: '%s'", this->name.string(), strerror(-err));
@@ -501,14 +455,12 @@
 }
 
 // ================================================================================
-void
-CommandSection::init(const char* command, va_list args)
-{
+void CommandSection::init(const char* command, va_list args) {
     va_list copied_args;
     int numOfArgs = 0;
 
     va_copy(copied_args, args);
-    while(va_arg(copied_args, const char*) != NULL) {
+    while (va_arg(copied_args, const char*) != NULL) {
         numOfArgs++;
     }
     va_end(copied_args);
@@ -518,41 +470,33 @@
 
     mCommand[0] = command;
     name = command;
-    for (int i=0; i<numOfArgs; i++) {
+    for (int i = 0; i < numOfArgs; i++) {
         const char* arg = va_arg(args, const char*);
-        mCommand[i+1] = arg;
+        mCommand[i + 1] = arg;
         name += " ";
         name += arg;
     }
-    mCommand[numOfArgs+1] = NULL;
+    mCommand[numOfArgs + 1] = NULL;
 }
 
 CommandSection::CommandSection(int id, const int64_t timeoutMs, const char* command, ...)
-    :Section(id, timeoutMs)
-{
+    : Section(id, timeoutMs) {
     va_list args;
     va_start(args, command);
     init(command, args);
     va_end(args);
 }
 
-CommandSection::CommandSection(int id, const char* command, ...)
-    :Section(id)
-{
+CommandSection::CommandSection(int id, const char* command, ...) : Section(id) {
     va_list args;
     va_start(args, command);
     init(command, args);
     va_end(args);
 }
 
-CommandSection::~CommandSection()
-{
-    free(mCommand);
-}
+CommandSection::~CommandSection() { free(mCommand); }
 
-status_t
-CommandSection::Execute(ReportRequestSet* requests) const
-{
+status_t CommandSection::Execute(ReportRequestSet* requests) const {
     FdBuffer buffer;
     Fpipe cmdPipe;
     Fpipe ihPipe;
@@ -571,13 +515,15 @@
     if (cmdPid == 0) {
         // replace command's stdout with ihPipe's write Fd
         if (dup2(cmdPipe.writeFd(), STDOUT_FILENO) != 1 || !ihPipe.close() || !cmdPipe.close()) {
-            ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(), strerror(errno));
+            ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(),
+                  strerror(errno));
             _exit(EXIT_FAILURE);
         }
-        execvp(this->mCommand[0], (char *const *) this->mCommand);
-        int err = errno; // record command error code
-        ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(), strerror(errno));
-        _exit(err); // exit with command error code
+        execvp(this->mCommand[0], (char* const*)this->mCommand);
+        int err = errno;  // record command error code
+        ALOGW("CommandSection '%s' failed in executing command: %s", this->name.string(),
+              strerror(errno));
+        _exit(err);  // exit with command error code
     }
     pid_t ihPid = fork_execute_incident_helper(this->id, this->name.string(), cmdPipe, ihPipe);
     if (ihPid == -1) {
@@ -589,24 +535,26 @@
     status_t readStatus = buffer.read(ihPipe.readFd(), this->timeoutMs);
     if (readStatus != NO_ERROR || buffer.timedOut()) {
         ALOGW("CommandSection '%s' failed to read data from incident helper: %s, timedout: %s",
-            this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
+              this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false");
         kill_child(cmdPid);
         kill_child(ihPid);
         return readStatus;
     }
 
-    // TODO: wait for command here has one trade-off: the failed status of command won't be detected until
+    // TODO: wait for command here has one trade-off: the failed status of command won't be detected
+    // until
     //       buffer timeout, but it has advatage on starting the data stream earlier.
     status_t cmdStatus = wait_child(cmdPid);
-    status_t ihStatus  = wait_child(ihPid);
+    status_t ihStatus = wait_child(ihPid);
     if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) {
-        ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incident helper: %s",
-            this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
+        ALOGW("CommandSection '%s' abnormal child processes, return status: command: %s, incident "
+              "helper: %s",
+              this->name.string(), strerror(-cmdStatus), strerror(-ihStatus));
         return cmdStatus != NO_ERROR ? cmdStatus : ihStatus;
     }
 
-    ALOGD("CommandSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
-            (int)buffer.durationMs());
+    VLOG("CommandSection '%s' wrote %zd bytes in %d ms", this->name.string(), buffer.size(),
+         (int)buffer.durationMs());
     status_t err = write_report_requests(this->id, buffer, requests);
     if (err != NO_ERROR) {
         ALOGW("CommandSection '%s' failed writing: %s", this->name.string(), strerror(-err));
@@ -617,9 +565,7 @@
 
 // ================================================================================
 DumpsysSection::DumpsysSection(int id, const char* service, ...)
-    :WorkerThreadSection(id),
-     mService(service)
-{
+    : WorkerThreadSection(id), mService(service) {
     name = "dumpsys ";
     name += service;
 
@@ -637,13 +583,9 @@
     va_end(args);
 }
 
-DumpsysSection::~DumpsysSection()
-{
-}
+DumpsysSection::~DumpsysSection() {}
 
-status_t
-DumpsysSection::BlockingCall(int pipeWriteFd) const
-{
+status_t DumpsysSection::BlockingCall(int pipeWriteFd) const {
     // checkService won't wait for the service to show up like getService will.
     sp<IBinder> service = defaultServiceManager()->checkService(mService);
 
@@ -667,30 +609,23 @@
 // initialization only once in Section.cpp.
 map<log_id_t, log_time> LogSection::gLastLogsRetrieved;
 
-LogSection::LogSection(int id, log_id_t logID)
-    :WorkerThreadSection(id),
-     mLogID(logID)
-{
+LogSection::LogSection(int id, log_id_t logID) : WorkerThreadSection(id), mLogID(logID) {
     name += "logcat ";
     name += android_log_id_to_name(logID);
     switch (logID) {
-    case LOG_ID_EVENTS:
-    case LOG_ID_STATS:
-    case LOG_ID_SECURITY:
-        mBinary = true;
-        break;
-    default:
-        mBinary = false;
+        case LOG_ID_EVENTS:
+        case LOG_ID_STATS:
+        case LOG_ID_SECURITY:
+            mBinary = true;
+            break;
+        default:
+            mBinary = false;
     }
 }
 
-LogSection::~LogSection()
-{
-}
+LogSection::~LogSection() {}
 
-static size_t
-trimTail(char const* buf, size_t len)
-{
+static size_t trimTail(char const* buf, size_t len) {
     while (len > 0) {
         char c = buf[len - 1];
         if (c == '\0' || c == ' ' || c == '\n' || c == '\r' || c == ':') {
@@ -706,17 +641,15 @@
     return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24);
 }
 
-status_t
-LogSection::BlockingCall(int pipeWriteFd) const
-{
+status_t LogSection::BlockingCall(int pipeWriteFd) const {
     status_t err = NO_ERROR;
     // Open log buffer and getting logs since last retrieved time if any.
     unique_ptr<logger_list, void (*)(logger_list*)> loggers(
-        gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end() ?
-        android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0) :
-        android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
-            gLastLogsRetrieved[mLogID], 0),
-        android_logger_list_free);
+            gLastLogsRetrieved.find(mLogID) == gLastLogsRetrieved.end()
+                    ? android_logger_list_alloc(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, 0)
+                    : android_logger_list_alloc_time(ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK,
+                                                     gLastLogsRetrieved[mLogID], 0),
+            android_logger_list_free);
 
     if (android_logger_open(loggers.get(), mLogID) == NULL) {
         ALOGW("LogSection %s: Can't get logger.", this->name.string());
@@ -727,7 +660,7 @@
     log_time lastTimestamp(0);
 
     ProtoOutputStream proto;
-    while (true) { // keeps reading until logd buffer is fully read.
+    while (true) {  // keeps reading until logd buffer is fully read.
         status_t err = android_logger_list_read(loggers.get(), &msg);
         // err = 0 - no content, unexpected connection drop or EOF.
         // err = +ive number - size of retrieved data from logger
@@ -742,7 +675,8 @@
         if (mBinary) {
             // remove the first uint32 which is tag's index in event log tags
             android_log_context context = create_android_log_parser(msg.msg() + sizeof(uint32_t),
-                    msg.len() - sizeof(uint32_t));;
+                                                                    msg.len() - sizeof(uint32_t));
+            ;
             android_log_list_element elem;
 
             lastTimestamp.tv_sec = msg.entry_v1.sec;
@@ -752,38 +686,46 @@
             long long token = proto.start(LogProto::BINARY_LOGS);
             proto.write(BinaryLogEntry::SEC, msg.entry_v1.sec);
             proto.write(BinaryLogEntry::NANOSEC, msg.entry_v1.nsec);
-            proto.write(BinaryLogEntry::UID, (int) msg.entry_v4.uid);
+            proto.write(BinaryLogEntry::UID, (int)msg.entry_v4.uid);
             proto.write(BinaryLogEntry::PID, msg.entry_v1.pid);
             proto.write(BinaryLogEntry::TID, msg.entry_v1.tid);
-            proto.write(BinaryLogEntry::TAG_INDEX, get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
+            proto.write(BinaryLogEntry::TAG_INDEX,
+                        get4LE(reinterpret_cast<uint8_t const*>(msg.msg())));
             do {
                 elem = android_log_read_next(context);
                 long long elemToken = proto.start(BinaryLogEntry::ELEMS);
                 switch (elem.type) {
                     case EVENT_TYPE_INT:
-                        proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_INT);
-                        proto.write(BinaryLogEntry::Elem::VAL_INT32, (int) elem.data.int32);
+                        proto.write(BinaryLogEntry::Elem::TYPE,
+                                    BinaryLogEntry::Elem::EVENT_TYPE_INT);
+                        proto.write(BinaryLogEntry::Elem::VAL_INT32, (int)elem.data.int32);
                         break;
                     case EVENT_TYPE_LONG:
-                        proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LONG);
-                        proto.write(BinaryLogEntry::Elem::VAL_INT64, (long long) elem.data.int64);
+                        proto.write(BinaryLogEntry::Elem::TYPE,
+                                    BinaryLogEntry::Elem::EVENT_TYPE_LONG);
+                        proto.write(BinaryLogEntry::Elem::VAL_INT64, (long long)elem.data.int64);
                         break;
                     case EVENT_TYPE_STRING:
-                        proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_STRING);
+                        proto.write(BinaryLogEntry::Elem::TYPE,
+                                    BinaryLogEntry::Elem::EVENT_TYPE_STRING);
                         proto.write(BinaryLogEntry::Elem::VAL_STRING, elem.data.string, elem.len);
                         break;
                     case EVENT_TYPE_FLOAT:
-                        proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_FLOAT);
+                        proto.write(BinaryLogEntry::Elem::TYPE,
+                                    BinaryLogEntry::Elem::EVENT_TYPE_FLOAT);
                         proto.write(BinaryLogEntry::Elem::VAL_FLOAT, elem.data.float32);
                         break;
                     case EVENT_TYPE_LIST:
-                        proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LIST);
+                        proto.write(BinaryLogEntry::Elem::TYPE,
+                                    BinaryLogEntry::Elem::EVENT_TYPE_LIST);
                         break;
                     case EVENT_TYPE_LIST_STOP:
-                        proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_LIST_STOP);
+                        proto.write(BinaryLogEntry::Elem::TYPE,
+                                    BinaryLogEntry::Elem::EVENT_TYPE_LIST_STOP);
                         break;
                     case EVENT_TYPE_UNKNOWN:
-                        proto.write(BinaryLogEntry::Elem::TYPE, BinaryLogEntry::Elem::EVENT_TYPE_UNKNOWN);
+                        proto.write(BinaryLogEntry::Elem::TYPE,
+                                    BinaryLogEntry::Elem::EVENT_TYPE_UNKNOWN);
                         break;
                 }
                 proto.end(elemToken);
@@ -811,7 +753,8 @@
             proto.write(TextLogEntry::PID, entry.pid);
             proto.write(TextLogEntry::TID, entry.tid);
             proto.write(TextLogEntry::TAG, entry.tag, trimTail(entry.tag, entry.tagLen));
-            proto.write(TextLogEntry::LOG, entry.message, trimTail(entry.message, entry.messageLen));
+            proto.write(TextLogEntry::LOG, entry.message,
+                        trimTail(entry.message, entry.messageLen));
             proto.end(token);
         }
     }
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index 80cc033..d644681 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -13,31 +13,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef SECTIONS_H
 #define SECTIONS_H
 
 #include "Reporter.h"
 
-#include <map>
 #include <stdarg.h>
+#include <map>
 
-#include <utils/String8.h>
 #include <utils/String16.h>
+#include <utils/String8.h>
 #include <utils/Vector.h>
 
 using namespace android;
 
-const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000; // 10 seconds
+const int64_t REMOTE_CALL_TIMEOUT_MS = 10 * 1000;  // 10 seconds
 
 /**
  * Base class for sections
  */
-class Section
-{
+class Section {
 public:
     const int id;
-    const int64_t timeoutMs; // each section must have a timeout
+    const int64_t timeoutMs;  // each section must have a timeout
     String8 name;
 
     Section(int id, const int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
@@ -49,8 +49,7 @@
 /**
  * Section that generates incident headers.
  */
-class HeaderSection : public Section
-{
+class HeaderSection : public Section {
 public:
     HeaderSection();
     virtual ~HeaderSection();
@@ -61,8 +60,7 @@
 /**
  * Section that generates incident metadata.
  */
-class MetadataSection : public Section
-{
+class MetadataSection : public Section {
 public:
     MetadataSection();
     virtual ~MetadataSection();
@@ -73,8 +71,7 @@
 /**
  * Section that reads in a file.
  */
-class FileSection : public Section
-{
+class FileSection : public Section {
 public:
     FileSection(int id, const char* filename, const int64_t timeoutMs = 5000 /* 5 seconds */);
     virtual ~FileSection();
@@ -83,14 +80,13 @@
 
 private:
     const char* mFilename;
-    bool mIsSysfs; // sysfs files are pollable but return POLLERR by default, handle it separately
+    bool mIsSysfs;  // sysfs files are pollable but return POLLERR by default, handle it separately
 };
 
 /**
  * Base class for sections that call a command that might need a timeout.
  */
-class WorkerThreadSection : public Section
-{
+class WorkerThreadSection : public Section {
 public:
     WorkerThreadSection(int id);
     virtual ~WorkerThreadSection();
@@ -103,8 +99,7 @@
 /**
  * Section that forks and execs a command, and puts stdout as the section.
  */
-class CommandSection : public Section
-{
+class CommandSection : public Section {
 public:
     CommandSection(int id, const int64_t timeoutMs, const char* command, ...);
 
@@ -123,8 +118,7 @@
 /**
  * Section that calls dumpsys on a system service.
  */
-class DumpsysSection : public WorkerThreadSection
-{
+class DumpsysSection : public WorkerThreadSection {
 public:
     DumpsysSection(int id, const char* service, ...);
     virtual ~DumpsysSection();
@@ -139,8 +133,7 @@
 /**
  * Section that reads from logd.
  */
-class LogSection : public WorkerThreadSection
-{
+class LogSection : public WorkerThreadSection {
     // global last log retrieved timestamp for each log_id_t.
     static map<log_id_t, log_time> gLastLogsRetrieved;
 
@@ -155,5 +148,4 @@
     bool mBinary;
 };
 
-#endif // SECTIONS_H
-
+#endif  // SECTIONS_H
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
new file mode 100644
index 0000000..2415860
--- /dev/null
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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 "incidentd_util.h"
+
+#include "section_list.h"
+
+const Privacy* get_privacy_of_section(int id) {
+    int l = 0;
+    int r = PRIVACY_POLICY_COUNT - 1;
+    while (l <= r) {
+        int mid = (l + r) >> 1;
+        const Privacy* p = PRIVACY_POLICY_LIST[mid];
+
+        if (p->field_id < (uint32_t)id) {
+            l = mid + 1;
+        } else if (p->field_id > (uint32_t)id) {
+            r = mid - 1;
+        } else {
+            return p;
+        }
+    }
+    return NULL;
+}
+
+// ================================================================================
+Fpipe::Fpipe() : mRead(), mWrite() {}
+
+Fpipe::~Fpipe() { close(); }
+
+bool Fpipe::close() {
+    mRead.reset();
+    mWrite.reset();
+    return true;
+}
+
+bool Fpipe::init() { return Pipe(&mRead, &mWrite); }
+
+int Fpipe::readFd() const { return mRead.get(); }
+
+int Fpipe::writeFd() const { return mWrite.get(); }
\ No newline at end of file
diff --git a/cmds/incidentd/src/io_util.h b/cmds/incidentd/src/incidentd_util.h
similarity index 74%
rename from cmds/incidentd/src/io_util.h
rename to cmds/incidentd/src/incidentd_util.h
index 320dd6c..09aa040 100644
--- a/cmds/incidentd/src/io_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -13,16 +13,18 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
-#ifndef IO_UTIL_H
-#define IO_UTIL_H
+#ifndef INCIDENTD_UTIL_H
+#define INCIDENTD_UTIL_H
 
-#include <stdint.h>
-#include <utils/Errors.h>
+#include <android-base/unique_fd.h>
 
-using namespace android;
+#include "Privacy.h"
 
-status_t write_all(int fd, uint8_t const* buf, size_t size);
+using namespace android::base;
+
+const Privacy* get_privacy_of_section(int id);
 
 class Fpipe {
 public:
@@ -35,7 +37,8 @@
     int writeFd() const;
 
 private:
-    int mFds[2];
+    unique_fd mRead;
+    unique_fd mWrite;
 };
 
-#endif // IO_UTIL_H
\ No newline at end of file
+#endif  // INCIDENTD_UTIL_H
\ No newline at end of file
diff --git a/cmds/incidentd/src/io_util.cpp b/cmds/incidentd/src/io_util.cpp
deleted file mode 100644
index 90f543e..0000000
--- a/cmds/incidentd/src/io_util.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2017 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 "incidentd"
-
-#include "io_util.h"
-
-#include <unistd.h>
-
-status_t write_all(int fd, uint8_t const* buf, size_t size)
-{
-    while (size > 0) {
-        ssize_t amt = TEMP_FAILURE_RETRY(::write(fd, buf, size));
-        if (amt < 0) {
-            return -errno;
-        }
-        size -= amt;
-        buf += amt;
-    }
-    return NO_ERROR;
-}
-
-Fpipe::Fpipe() {}
-
-Fpipe::~Fpipe() { close(); }
-
-bool Fpipe::close() { return !(::close(mFds[0]) || ::close(mFds[1])); }
-
-bool Fpipe::init() { return pipe(mFds) != -1; }
-
-int Fpipe::readFd() const { return mFds[0]; }
-
-int Fpipe::writeFd() const { return mFds[1]; }
diff --git a/cmds/incidentd/src/main.cpp b/cmds/incidentd/src/main.cpp
index 3a7511d..38b7449 100644
--- a/cmds/incidentd/src/main.cpp
+++ b/cmds/incidentd/src/main.cpp
@@ -13,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
 
 #include "IncidentService.h"
 
@@ -23,25 +22,22 @@
 #include <binder/IServiceManager.h>
 #include <binder/ProcessState.h>
 #include <binder/Status.h>
-#include <cutils/log.h>
 #include <utils/Looper.h>
 #include <utils/StrongPointer.h>
 
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
 
 using namespace android;
 
 // ================================================================================
-int
-main(int /*argc*/, char** /*argv*/)
-{
+int main(int /*argc*/, char** /*argv*/) {
     // Set up the looper
     sp<Looper> looper(Looper::prepare(0 /* opts */));
 
     // Set up the binder
     sp<ProcessState> ps(ProcessState::self());
-    ps->setThreadPoolMaxThreadCount(1); // everything is oneway, let it queue and save ram
+    ps->setThreadPoolMaxThreadCount(1);  // everything is oneway, let it queue and save ram
     ps->startThreadPool();
     ps->giveThreadPoolName();
     IPCThreadState::self()->disableBackgroundScheduling(true);
diff --git a/cmds/incidentd/src/report_directory.cpp b/cmds/incidentd/src/report_directory.cpp
index 20111d8..b71c066 100644
--- a/cmds/incidentd/src/report_directory.cpp
+++ b/cmds/incidentd/src/report_directory.cpp
@@ -13,19 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-#define LOG_TAG "incidentd"
+#include "Log.h"
 
 #include "report_directory.h"
 
-#include <cutils/log.h>
 #include <private/android_filesystem_config.h>
 #include <utils/String8.h>
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <dirent.h>
 #include <libgen.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include <vector>
@@ -33,9 +31,7 @@
 using namespace android;
 using namespace std;
 
-status_t
-create_directory(const char* directory)
-{
+status_t create_directory(const char* directory) {
     struct stat st;
     status_t err = NO_ERROR;
     char* dir = strdup(directory);
@@ -75,14 +71,14 @@
         goto done;
     }
     if ((st.st_mode & 0777) != 0770) {
-        ALOGE("No incident reports today. Mode is %0o on report directory %s",
-                st.st_mode, directory);
+        ALOGE("No incident reports today. Mode is %0o on report directory %s", st.st_mode,
+              directory);
         err = BAD_VALUE;
         goto done;
     }
     if (st.st_uid != AID_INCIDENTD || st.st_gid != AID_INCIDENTD) {
         ALOGE("No incident reports today. Owner is %d and group is %d on report directory %s",
-                st.st_uid, st.st_gid, directory);
+              st.st_uid, st.st_gid, directory);
         err = BAD_VALUE;
         goto done;
     }
@@ -92,20 +88,17 @@
     return err;
 }
 
-static bool
-stat_mtime_cmp(const pair<String8,struct stat>& a, const pair<String8,struct stat>& b)
-{
+static bool stat_mtime_cmp(const pair<String8, struct stat>& a,
+                           const pair<String8, struct stat>& b) {
     return a.second.st_mtime < b.second.st_mtime;
 }
 
-void
-clean_directory(const char* directory, off_t maxSize, size_t maxCount)
-{
+void clean_directory(const char* directory, off_t maxSize, size_t maxCount) {
     DIR* dir;
     struct dirent* entry;
     struct stat st;
 
-    vector<pair<String8,struct stat>> files;
+    vector<pair<String8, struct stat>> files;
 
     if ((dir = opendir(directory)) == NULL) {
         ALOGE("Couldn't open incident directory: %s", directory);
@@ -131,7 +124,7 @@
         if (!S_ISREG(st.st_mode)) {
             continue;
         }
-        files.push_back(pair<String8,struct stat>(filename, st));
+        files.push_back(pair<String8, struct stat>(filename, st));
 
         totalSize += st.st_size;
         totalCount++;
@@ -148,8 +141,8 @@
     sort(files.begin(), files.end(), stat_mtime_cmp);
 
     // Remove files until we're under our limits.
-    for (vector<pair<String8,struct stat>>::iterator it = files.begin();
-            it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
+    for (vector<pair<String8, struct stat>>::iterator it = files.begin();
+         it != files.end() && totalSize >= maxSize && totalCount >= maxCount; it++) {
         remove(it->first.string());
         totalSize -= it->second.st_size;
         totalCount--;
diff --git a/cmds/incidentd/src/report_directory.h b/cmds/incidentd/src/report_directory.h
index bed4f86..2a3cf4c 100644
--- a/cmds/incidentd/src/report_directory.h
+++ b/cmds/incidentd/src/report_directory.h
@@ -13,17 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef DIRECTORY_CLEANER_H
 #define DIRECTORY_CLEANER_H
 
+#include <sys/types.h>
 #include <utils/Errors.h>
 
-#include <sys/types.h>
-
-using namespace android;
-
-status_t create_directory(const char* directory);
+android::status_t create_directory(const char* directory);
 void clean_directory(const char* directory, off_t maxSize, size_t maxCount);
 
-#endif // DIRECTORY_CLEANER_H
+#endif  // DIRECTORY_CLEANER_H
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
index ddc0505..697e66f 100644
--- a/cmds/incidentd/src/section_list.h
+++ b/cmds/incidentd/src/section_list.h
@@ -13,11 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #ifndef SECTION_LIST_H
 #define SECTION_LIST_H
 
-#include <log/log_event_list.h> // include log_id_t enums.
+#include <log/log_event_list.h>  // include log_id_t enums.
 
 #include "Privacy.h"
 #include "Section.h"
@@ -36,5 +37,4 @@
 
 extern const int PRIVACY_POLICY_COUNT;
 
-#endif // SECTION_LIST_H
-
+#endif  // SECTION_LIST_H
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index 3fd2ed8..956c8d3 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -11,11 +11,10 @@
 // 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 "incidentd"
+#include "Log.h"
 
 #include "FdBuffer.h"
-#include "io_util.h"
+#include "incidentd_util.h"
 
 #include <android-base/file.h>
 #include <android-base/test_utils.h>
@@ -48,7 +47,7 @@
     }
 
     void AssertBufferContent(const char* expected) {
-        int i=0;
+        int i = 0;
         EncodedBuffer::iterator it = buffer.data();
         while (it.hasNext()) {
             ASSERT_EQ(it.next(), expected[i++]);
@@ -100,7 +99,7 @@
     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
     ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
 
-    int i=0;
+    int i = 0;
     EncodedBuffer::iterator it = buffer.data();
     while (it.hasNext()) {
         EXPECT_EQ(it.next(), (uint8_t)testdata[i++]);
@@ -118,7 +117,7 @@
 
     if (pid == 0) {
         close(c2pPipe.readFd());
-        while(true) {
+        while (true) {
             write(c2pPipe.writeFd(), "poo", 3);
             sleep(1);
         }
@@ -130,7 +129,7 @@
         ASSERT_EQ(NO_ERROR, status);
         EXPECT_TRUE(buffer.timedOut());
 
-        kill(pid, SIGKILL); // reap the child process
+        kill(pid, SIGKILL);  // reap the child process
     }
 }
 
@@ -155,8 +154,8 @@
         close(p2cPipe.readFd());
         close(c2pPipe.writeFd());
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
-            p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+                                                             c2pPipe.readFd(), READ_TIMEOUT));
         AssertBufferReadSuccessful(HEAD.size() + testdata.size());
         AssertBufferContent(expected.c_str());
         wait(&pid);
@@ -187,8 +186,8 @@
         close(p2cPipe.readFd());
         close(c2pPipe.writeFd());
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
-            p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+                                                             c2pPipe.readFd(), READ_TIMEOUT));
         AssertBufferReadSuccessful(HEAD.size() + testdata.size());
         AssertBufferContent(expected.c_str());
         wait(&pid);
@@ -212,8 +211,8 @@
         close(p2cPipe.readFd());
         close(c2pPipe.writeFd());
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
-            p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+                                                             c2pPipe.readFd(), READ_TIMEOUT));
         AssertBufferReadSuccessful(0);
         AssertBufferContent("");
         wait(&pid);
@@ -222,7 +221,7 @@
 
 TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
     const std::string testFile = kTestDataPath + "morethan4MB.txt";
-    size_t fourMB = (size_t) 4 * 1024 * 1024;
+    size_t fourMB = (size_t)4 * 1024 * 1024;
     int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
     ASSERT_NE(fd, -1);
     int pid = fork();
@@ -239,8 +238,8 @@
         close(p2cPipe.readFd());
         close(c2pPipe.writeFd());
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd,
-            p2cPipe.writeFd(), c2pPipe.readFd(), READ_TIMEOUT));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(),
+                                                             c2pPipe.readFd(), READ_TIMEOUT));
         EXPECT_EQ(buffer.size(), fourMB);
         EXPECT_FALSE(buffer.timedOut());
         EXPECT_TRUE(buffer.truncated());
@@ -276,9 +275,9 @@
         close(p2cPipe.readFd());
         close(c2pPipe.writeFd());
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd,
-            p2cPipe.writeFd(), c2pPipe.readFd(), QUICK_TIMEOUT_MS));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
+                                                             c2pPipe.readFd(), QUICK_TIMEOUT_MS));
         EXPECT_TRUE(buffer.timedOut());
-        kill(pid, SIGKILL); // reap the child process
+        kill(pid, SIGKILL);  // reap the child process
     }
 }
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index c7bfe55..7ea9bbf 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -11,8 +11,7 @@
 // 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 "incidentd"
+#include "Log.h"
 
 #include "FdBuffer.h"
 #include "PrivacyBuffer.h"
@@ -37,13 +36,12 @@
 const uint8_t STRING_TYPE = 9;
 const uint8_t MESSAGE_TYPE = 11;
 const string STRING_FIELD_0 = "\x02\viamtestdata";
-const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
+const string VARINT_FIELD_1 = "\x08\x96\x01";  // 150
 const string STRING_FIELD_2 = "\x12\vwhatthefuck";
-const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
-const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff"; // -1
+const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff";  // -1
+const string FIX32_FIELD_4 = "\x25\xff\xff\xff\xff";                  // -1
 const string MESSAGE_FIELD_5 = "\x2a\x10" + VARINT_FIELD_1 + STRING_FIELD_2;
 
-
 class PrivacyBufferTest : public Test {
 public:
     virtual ~PrivacyBufferTest() {
@@ -55,9 +53,7 @@
         }
     }
 
-    virtual void SetUp() override {
-        ASSERT_NE(tf.fd, -1);
-    }
+    virtual void SetUp() override { ASSERT_NE(tf.fd, -1); }
 
     void writeToFdBuffer(string str) {
         ASSERT_TRUE(WriteStringToFile(str, tf.path));
@@ -81,11 +77,11 @@
     }
 
     void assertStripByFields(uint8_t dest, string expected, int size, Privacy* privacy, ...) {
-        Privacy* list[size+1];
+        Privacy* list[size + 1];
         list[0] = privacy;
         va_list args;
         va_start(args, privacy);
-        for (int i=1; i<size; i++) {
+        for (int i = 1; i < size; i++) {
             Privacy* p = va_arg(args, Privacy*);
             list[i] = p;
         }
@@ -115,13 +111,14 @@
     }
 
     FdBuffer buffer;
+
 private:
     TemporaryFile tf;
     // Littering this code with unique_ptr (or similar) is ugly, so we just
     // mass-free everything after the test completes.
-    std::vector<Privacy *> privacies;
+    std::vector<Privacy*> privacies;
 
-    Privacy *new_uninit_privacy() {
+    Privacy* new_uninit_privacy() {
         Privacy* p = new Privacy;
         privacies.push_back(p);
         return p;
@@ -165,63 +162,69 @@
 
 TEST_F(PrivacyBufferTest, NoStripVarintField) {
     writeToFdBuffer(VARINT_FIELD_1);
-    assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1, create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC));
+    assertStripByFields(DEST_EXPLICIT, VARINT_FIELD_1, 1,
+                        create_privacy(1, OTHER_TYPE, DEST_AUTOMATIC));
 }
 
 TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_String) {
     writeToFdBuffer(STRING_FIELD_2);
-    assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1, create_privacy(2, STRING_TYPE, DEST_AUTOMATIC));
+    assertStripByFields(DEST_EXPLICIT, STRING_FIELD_2, 1,
+                        create_privacy(2, STRING_TYPE, DEST_AUTOMATIC));
 }
 
 TEST_F(PrivacyBufferTest, NoStripFixed64Field) {
     writeToFdBuffer(FIX64_FIELD_3);
-    assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1, create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC));
+    assertStripByFields(DEST_EXPLICIT, FIX64_FIELD_3, 1,
+                        create_privacy(3, OTHER_TYPE, DEST_AUTOMATIC));
 }
 
 TEST_F(PrivacyBufferTest, NoStripFixed32Field) {
     writeToFdBuffer(FIX32_FIELD_4);
-    assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1, create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC));
+    assertStripByFields(DEST_EXPLICIT, FIX32_FIELD_4, 1,
+                        create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC));
 }
 
 TEST_F(PrivacyBufferTest, NoStripLengthDelimitedField_Message) {
     writeToFdBuffer(MESSAGE_FIELD_5);
-    assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1, create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC));
+    assertStripByFields(DEST_EXPLICIT, MESSAGE_FIELD_5, 1,
+                        create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC));
 }
 
 TEST_F(PrivacyBufferTest, StripVarintAndString) {
-    writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
-            + FIX64_FIELD_3 + FIX32_FIELD_4);
+    writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 +
+                    FIX32_FIELD_4);
     string expected = STRING_FIELD_0 + FIX64_FIELD_3 + FIX32_FIELD_4;
-    assertStripByFields(DEST_EXPLICIT, expected, 2,
-            create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(2, STRING_TYPE, DEST_LOCAL));
+    assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(1, OTHER_TYPE, DEST_LOCAL),
+                        create_privacy(2, STRING_TYPE, DEST_LOCAL));
 }
 
 TEST_F(PrivacyBufferTest, StripVarintAndFixed64) {
-    writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2
-            + FIX64_FIELD_3 + FIX32_FIELD_4);
+    writeToFdBuffer(STRING_FIELD_0 + VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3 +
+                    FIX32_FIELD_4);
     string expected = STRING_FIELD_0 + STRING_FIELD_2 + FIX32_FIELD_4;
-    assertStripByFields(DEST_EXPLICIT, expected, 2,
-            create_privacy(1, OTHER_TYPE, DEST_LOCAL), create_privacy(3, OTHER_TYPE, DEST_LOCAL));
+    assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(1, OTHER_TYPE, DEST_LOCAL),
+                        create_privacy(3, OTHER_TYPE, DEST_LOCAL));
 }
 
 TEST_F(PrivacyBufferTest, StripVarintInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5);
-    Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+    Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
     string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
     assertStripByFields(DEST_EXPLICIT, expected, 1, create_message_privacy(5, list));
 }
 
 TEST_F(PrivacyBufferTest, StripFix64AndVarintInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + FIX64_FIELD_3 + MESSAGE_FIELD_5);
-    Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+    Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
     string expected = STRING_FIELD_0 + "\x2a\xd" + STRING_FIELD_2;
-    assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL), create_message_privacy(5, list));
+    assertStripByFields(DEST_EXPLICIT, expected, 2, create_privacy(3, OTHER_TYPE, DEST_LOCAL),
+                        create_message_privacy(5, list));
 }
 
 TEST_F(PrivacyBufferTest, ClearAndStrip) {
     string data = STRING_FIELD_0 + VARINT_FIELD_1;
     writeToFdBuffer(data);
-    Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+    Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
     EncodedBuffer::iterator bufData = buffer.data();
     PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
     PrivacySpec spec1 = PrivacySpec::new_spec(DEST_EXPLICIT);
@@ -235,7 +238,7 @@
 
 TEST_F(PrivacyBufferTest, BadDataInFdBuffer) {
     writeToFdBuffer("iambaddata");
-    Privacy* list[] = { create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL };
+    Privacy* list[] = {create_privacy(4, OTHER_TYPE, DEST_AUTOMATIC), NULL};
     EncodedBuffer::iterator bufData = buffer.data();
     PrivacyBuffer privacyBuf(create_message_privacy(300, list), bufData);
     PrivacySpec spec;
@@ -244,8 +247,8 @@
 
 TEST_F(PrivacyBufferTest, BadDataInNestedMessage) {
     writeToFdBuffer(STRING_FIELD_0 + MESSAGE_FIELD_5 + "aoeoe");
-    Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
-    Privacy* field5[] = { create_message_privacy(5, list), NULL };
+    Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
+    Privacy* field5[] = {create_message_privacy(5, list), NULL};
     EncodedBuffer::iterator bufData = buffer.data();
     PrivacyBuffer privacyBuf(create_message_privacy(300, field5), bufData);
     PrivacySpec spec;
@@ -256,7 +259,7 @@
     string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5;
     writeToFdBuffer(input);
     Privacy* field5 = create_message_privacy(5, NULL);
-    Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL };
+    Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), field5, NULL};
     field5->children = list;
     string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2;
     assertStrip(DEST_EXPLICIT, expected, field5);
@@ -264,7 +267,7 @@
 
 TEST_F(PrivacyBufferTest, AutoMessage) {
     writeToFdBuffer(STRING_FIELD_2 + MESSAGE_FIELD_5);
-    Privacy* list[] = { create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL };
+    Privacy* list[] = {create_privacy(1, OTHER_TYPE, DEST_LOCAL), NULL};
     Privacy* autoMsg = create_privacy(5, MESSAGE_TYPE, DEST_AUTOMATIC);
     autoMsg->children = list;
     string expected = "\x2a\xd" + STRING_FIELD_2;
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index a1e3c34..bd359ac 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -11,8 +11,7 @@
 // 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 "incidentd"
+#include "Log.h"
 
 #include "Reporter.h"
 
@@ -26,7 +25,6 @@
 #include <gtest/gtest.h>
 #include <string.h>
 
-
 using namespace android;
 using namespace android::base;
 using namespace android::binder;
@@ -35,8 +33,7 @@
 using ::testing::StrEq;
 using ::testing::Test;
 
-class TestListener : public IIncidentReportStatusListener
-{
+class TestListener : public IIncidentReportStatusListener {
 public:
     int startInvoked;
     int finishInvoked;
@@ -44,8 +41,8 @@
     map<int, int> startSections;
     map<int, int> finishSections;
 
-    TestListener() : startInvoked(0), finishInvoked(0), failedInvoked(0) {};
-    virtual ~TestListener() {};
+    TestListener() : startInvoked(0), finishInvoked(0), failedInvoked(0){};
+    virtual ~TestListener(){};
 
     virtual Status onReportStarted() {
         startInvoked++;
@@ -53,16 +50,14 @@
     };
     virtual Status onReportSectionStatus(int section, int status) {
         switch (status) {
-        case IIncidentReportStatusListener::STATUS_STARTING:
-            if (startSections.count(section) == 0)
-                startSections[section] = 0;
-            startSections[section] = startSections[section] + 1;
-            break;
-        case IIncidentReportStatusListener::STATUS_FINISHED:
-            if (finishSections.count(section) == 0)
-                finishSections[section] = 0;
-            finishSections[section] = finishSections[section] + 1;
-            break;
+            case IIncidentReportStatusListener::STATUS_STARTING:
+                if (startSections.count(section) == 0) startSections[section] = 0;
+                startSections[section] = startSections[section] + 1;
+                break;
+            case IIncidentReportStatusListener::STATUS_FINISHED:
+                if (finishSections.count(section) == 0) finishSections[section] = 0;
+                finishSections[section] = finishSections[section] + 1;
+                break;
         }
         return Status::ok();
     };
@@ -156,7 +151,8 @@
 
     string result;
     ReadFileToString(tf.path, &result);
-    EXPECT_THAT(result, StrEq("\n\x2" "\b\f"));
+    EXPECT_THAT(result, StrEq("\n\x2"
+                              "\b\f"));
 
     EXPECT_EQ(l->startInvoked, 2);
     EXPECT_EQ(l->finishInvoked, 2);
@@ -178,7 +174,11 @@
     ASSERT_EQ(Reporter::REPORT_FINISHED, reporter->runReport());
     vector<string> results = InspectFiles();
     ASSERT_EQ((int)results.size(), 1);
-    EXPECT_EQ(results[0], "\n\x2" "\b\f\n\x6" "\x12\x4" "abcd");
+    EXPECT_EQ(results[0],
+              "\n\x2"
+              "\b\f\n\x6"
+              "\x12\x4"
+              "abcd");
 }
 
 TEST_F(ReporterTest, ReportMetadata) {
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 5752a67..a1f4fdc 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -11,8 +11,7 @@
 // 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 "incidentd"
+#include "Log.h"
 
 #include "Section.h"
 
@@ -30,9 +29,9 @@
 
 const int QUICK_TIMEOUT_MS = 100;
 
-const string VARINT_FIELD_1 = "\x08\x96\x01"; // 150
+const string VARINT_FIELD_1 = "\x08\x96\x01";  // 150
 const string STRING_FIELD_2 = "\x12\vwhatthefuck";
-const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff"; // -1
+const string FIX64_FIELD_3 = "\x19\xff\xff\xff\xff\xff\xff\xff\xff";  // -1
 
 using namespace android::base;
 using namespace android::binder;
@@ -44,11 +43,10 @@
 
 // NOTICE: this test requires /system/bin/incident_helper is installed.
 
-class SimpleListener : public IIncidentReportStatusListener
-{
+class SimpleListener : public IIncidentReportStatusListener {
 public:
-    SimpleListener() {};
-    virtual ~SimpleListener() {};
+    SimpleListener(){};
+    virtual ~SimpleListener(){};
 
     virtual Status onReportStarted() { return Status::ok(); };
     virtual Status onReportSectionStatus(int /*section*/, int /*status*/) { return Status::ok(); };
@@ -84,7 +82,9 @@
     string content;
     CaptureStdout();
     ASSERT_EQ(NO_ERROR, hs.Execute(&requests));
-    EXPECT_THAT(GetCapturedStdout(), StrEq("\n\x5" "\x12\x3" "axe\n\x05\x12\x03pup"));
+    EXPECT_THAT(GetCapturedStdout(), StrEq("\n\x5"
+                                           "\x12\x3"
+                                           "axe\n\x05\x12\x03pup"));
 
     EXPECT_TRUE(ReadFileToString(output2.path, &content));
     EXPECT_THAT(content, StrEq("\n\x05\x12\x03pup"));
@@ -271,12 +271,12 @@
 
     string content, expect;
     expect = VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3;
-    char c = (char) expect.size();
+    char c = (char)expect.size();
     EXPECT_TRUE(ReadFileToString(output1.path, &content));
     EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
 
     expect = STRING_FIELD_2 + FIX64_FIELD_3;
-    c = (char) expect.size();
+    c = (char)expect.size();
     EXPECT_TRUE(ReadFileToString(output2.path, &content));
     EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
 
@@ -315,7 +315,7 @@
 
     string content, expect;
     expect = STRING_FIELD_2 + FIX64_FIELD_3;
-    char c = (char) expect.size();
+    char c = (char)expect.size();
 
     // output1 and output2 are the same
     EXPECT_TRUE(ReadFileToString(output1.path, &content));
@@ -324,7 +324,7 @@
     EXPECT_THAT(content, StrEq(string("\x02") + c + expect));
 
     // output3 has only auto field
-    c = (char) STRING_FIELD_2.size();
+    c = (char)STRING_FIELD_2.size();
     EXPECT_TRUE(ReadFileToString(output3.path, &content));
     EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2));
 }
\ No newline at end of file
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index 1d6213f..bd2d15c 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -1,25 +1,17 @@
 // This file is a dummy section_list.cpp used for test only.
 #include "section_list.h"
 
-const Section* SECTION_LIST[] = {
-    NULL
-};
+const Section* SECTION_LIST[] = {NULL};
 
-Privacy sub_field_1 { 1, 1, NULL, DEST_LOCAL, NULL };
-Privacy sub_field_2 { 2, 9, NULL, DEST_AUTOMATIC, NULL };
+Privacy sub_field_1{1, 1, NULL, DEST_LOCAL, NULL};
+Privacy sub_field_2{2, 9, NULL, DEST_AUTOMATIC, NULL};
 
-Privacy* list[] = {
-    &sub_field_1,
-    &sub_field_2,
-    NULL };
+Privacy* list[] = {&sub_field_1, &sub_field_2, NULL};
 
-Privacy field_0 { 0, 11, list, DEST_EXPLICIT, NULL };
-Privacy field_1 { 1, 9, NULL, DEST_AUTOMATIC, NULL };
+Privacy field_0{0, 11, list, DEST_EXPLICIT, NULL};
+Privacy field_1{1, 9, NULL, DEST_AUTOMATIC, NULL};
 
-Privacy* final_list[] = {
-    &field_0,
-    &field_1
-};
+Privacy* final_list[] = {&field_0, &field_1};
 
 const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(final_list);
 
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index fbb0fdd..d0f55ab 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -59,45 +59,71 @@
 }
 
 void ConfigManager::AddListener(const sp<ConfigListener>& listener) {
+    lock_guard<mutex> lock(mMutex);
     mListeners.push_back(listener);
 }
 
 void ConfigManager::UpdateConfig(const ConfigKey& key, const StatsdConfig& config) {
-    // Add to set
-    mConfigs.insert(key);
+    vector<sp<ConfigListener>> broadcastList;
+    {
+        lock_guard <mutex> lock(mMutex);
 
-    // Save to disk
-    update_saved_configs(key, config);
+        // Add to set
+        mConfigs.insert(key);
+
+        // Save to disk
+        update_saved_configs_locked(key, config);
+
+        for (sp<ConfigListener> listener : mListeners) {
+            broadcastList.push_back(listener);
+        }
+    }
 
     // Tell everyone
-    for (auto& listener : mListeners) {
+    for (sp<ConfigListener> listener:broadcastList) {
         listener->OnConfigUpdated(key, config);
     }
 }
 
 void ConfigManager::SetConfigReceiver(const ConfigKey& key, const sp<IBinder>& intentSender) {
+    lock_guard<mutex> lock(mMutex);
     mConfigReceivers[key] = intentSender;
 }
 
 void ConfigManager::RemoveConfigReceiver(const ConfigKey& key) {
+    lock_guard<mutex> lock(mMutex);
     mConfigReceivers.erase(key);
 }
 
 void ConfigManager::RemoveConfig(const ConfigKey& key) {
-    auto it = mConfigs.find(key);
-    if (it != mConfigs.end()) {
-        // Remove from map
-        mConfigs.erase(it);
+    vector<sp<ConfigListener>> broadcastList;
+    {
+        lock_guard <mutex> lock(mMutex);
 
-        // Tell everyone
-        for (auto& listener : mListeners) {
-            listener->OnConfigRemoved(key);
+        auto it = mConfigs.find(key);
+        if (it != mConfigs.end()) {
+            // Remove from map
+            mConfigs.erase(it);
+
+            for (sp<ConfigListener> listener : mListeners) {
+                broadcastList.push_back(listener);
+            }
         }
+
+        auto itReceiver = mConfigReceivers.find(key);
+        if (itReceiver != mConfigReceivers.end()) {
+            // Remove from map
+            mConfigReceivers.erase(itReceiver);
+        }
+
+        // Remove from disk. There can still be a lingering file on disk so we check
+        // whether or not the config was on memory.
+        remove_saved_configs(key);
     }
 
-    // Remove from disk. There can still be a lingering file on disk so we check
-    // whether or not the config was on memory.
-    remove_saved_configs(key);
+    for (sp<ConfigListener> listener:broadcastList) {
+        listener->OnConfigRemoved(key);
+    }
 }
 
 void ConfigManager::remove_saved_configs(const ConfigKey& key) {
@@ -107,23 +133,32 @@
 
 void ConfigManager::RemoveConfigs(int uid) {
     vector<ConfigKey> removed;
+    vector<sp<ConfigListener>> broadcastList;
+    {
+        lock_guard <mutex> lock(mMutex);
 
-    for (auto it = mConfigs.begin(); it != mConfigs.end();) {
-        // Remove from map
-        if (it->GetUid() == uid) {
-            remove_saved_configs(*it);
-            removed.push_back(*it);
-            mConfigReceivers.erase(*it);
-            it = mConfigs.erase(it);
-        } else {
-            it++;
+
+        for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+            // Remove from map
+            if (it->GetUid() == uid) {
+                remove_saved_configs(*it);
+                removed.push_back(*it);
+                mConfigReceivers.erase(*it);
+                it = mConfigs.erase(it);
+            } else {
+                it++;
+            }
+        }
+
+        for (sp<ConfigListener> listener : mListeners) {
+            broadcastList.push_back(listener);
         }
     }
 
     // Remove separately so if they do anything in the callback they can't mess up our iteration.
     for (auto& key : removed) {
         // Tell everyone
-        for (auto& listener : mListeners) {
+        for (sp<ConfigListener> listener:broadcastList) {
             listener->OnConfigRemoved(key);
         }
     }
@@ -131,27 +166,38 @@
 
 void ConfigManager::RemoveAllConfigs() {
     vector<ConfigKey> removed;
+    vector<sp<ConfigListener>> broadcastList;
+    {
+        lock_guard <mutex> lock(mMutex);
 
-    for (auto it = mConfigs.begin(); it != mConfigs.end();) {
-        // Remove from map
-        removed.push_back(*it);
-        auto receiverIt = mConfigReceivers.find(*it);
-        if (receiverIt != mConfigReceivers.end()) {
-            mConfigReceivers.erase(*it);
+
+        for (auto it = mConfigs.begin(); it != mConfigs.end();) {
+            // Remove from map
+            removed.push_back(*it);
+            auto receiverIt = mConfigReceivers.find(*it);
+            if (receiverIt != mConfigReceivers.end()) {
+                mConfigReceivers.erase(*it);
+            }
+            it = mConfigs.erase(it);
         }
-        it = mConfigs.erase(it);
+
+        for (sp<ConfigListener> listener : mListeners) {
+            broadcastList.push_back(listener);
+        }
     }
 
     // Remove separately so if they do anything in the callback they can't mess up our iteration.
     for (auto& key : removed) {
         // Tell everyone
-        for (auto& listener : mListeners) {
+        for (sp<ConfigListener> listener:broadcastList) {
             listener->OnConfigRemoved(key);
         }
     }
 }
 
 vector<ConfigKey> ConfigManager::GetAllConfigKeys() const {
+    lock_guard<mutex> lock(mMutex);
+
     vector<ConfigKey> ret;
     for (auto it = mConfigs.cbegin(); it != mConfigs.cend(); ++it) {
         ret.push_back(*it);
@@ -160,6 +206,8 @@
 }
 
 const sp<android::IBinder> ConfigManager::GetConfigReceiver(const ConfigKey& key) const {
+    lock_guard<mutex> lock(mMutex);
+
     auto it = mConfigReceivers.find(key);
     if (it == mConfigReceivers.end()) {
         return nullptr;
@@ -169,6 +217,8 @@
 }
 
 void ConfigManager::Dump(FILE* out) {
+    lock_guard<mutex> lock(mMutex);
+
     fprintf(out, "CONFIGURATIONS (%d)\n", (int)mConfigs.size());
     fprintf(out, "     uid name\n");
     for (const auto& key : mConfigs) {
@@ -180,7 +230,7 @@
     }
 }
 
-void ConfigManager::update_saved_configs(const ConfigKey& key, const StatsdConfig& config) {
+void ConfigManager::update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config) {
     // If there is a pre-existing config with same key we should first delete it.
     remove_saved_configs(key);
 
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index a2b2a0c..a0c1c1c 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -21,6 +21,7 @@
 #include "config/ConfigListener.h"
 
 #include <map>
+#include <mutex>
 #include <set>
 #include <string>
 
@@ -109,10 +110,12 @@
     void Dump(FILE* out);
 
 private:
+    mutable std::mutex mMutex;
+
     /**
      * Save the configs to disk.
      */
-    void update_saved_configs(const ConfigKey& key, const StatsdConfig& config);
+    void update_saved_configs_locked(const ConfigKey& key, const StatsdConfig& config);
 
     /**
      * Remove saved configs from disk.
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 944764b..4612009 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -233,6 +233,11 @@
                     (matcher.eq_int() == values[i].mValue.int_value)) {
                     return true;
                 }
+                // eq_int covers both int and long.
+                if (values[i].mValue.getType() == LONG &&
+                    (matcher.eq_int() == values[i].mValue.long_value)) {
+                    return true;
+                }
             }
             return false;
         case FieldValueMatcher::ValueMatcherCase::kLtInt:
@@ -241,6 +246,11 @@
                     (values[i].mValue.int_value < matcher.lt_int())) {
                     return true;
                 }
+                // lt_int covers both int and long.
+                if (values[i].mValue.getType() == LONG &&
+                    (values[i].mValue.long_value < matcher.lt_int())) {
+                    return true;
+                }
             }
             return false;
         case FieldValueMatcher::ValueMatcherCase::kGtInt:
@@ -249,6 +259,11 @@
                     (values[i].mValue.int_value > matcher.gt_int())) {
                     return true;
                 }
+                // gt_int covers both int and long.
+                if (values[i].mValue.getType() == LONG &&
+                    (values[i].mValue.long_value > matcher.gt_int())) {
+                    return true;
+                }
             }
             return false;
         case FieldValueMatcher::ValueMatcherCase::kLtFloat:
@@ -273,6 +288,11 @@
                     (values[i].mValue.int_value <= matcher.lte_int())) {
                     return true;
                 }
+                // lte_int covers both int and long.
+                if (values[i].mValue.getType() == LONG &&
+                    (values[i].mValue.long_value <= matcher.lte_int())) {
+                    return true;
+                }
             }
             return false;
         case FieldValueMatcher::ValueMatcherCase::kGteInt:
@@ -281,6 +301,11 @@
                     (values[i].mValue.int_value >= matcher.gte_int())) {
                     return true;
                 }
+                // gte_int covers both int and long.
+                if (values[i].mValue.getType() == LONG &&
+                    (values[i].mValue.long_value >= matcher.gte_int())) {
+                    return true;
+                }
             }
             return false;
         default:
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 3b7936d..9c65371 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -111,12 +111,6 @@
 
 sp<AnomalyTracker> DurationMetricProducer::addAnomalyTracker(const Alert &alert) {
     std::lock_guard<std::mutex> lock(mMutex);
-    if (alert.trigger_if_sum_gt() > alert.num_buckets() * mBucketSizeNs) {
-        ALOGW("invalid alert: threshold (%f) > possible recordable value (%d x %lld)",
-              alert.trigger_if_sum_gt(), alert.num_buckets(),
-              (long long)mBucketSizeNs);
-        return nullptr;
-    }
     sp<DurationAnomalyTracker> anomalyTracker = new DurationAnomalyTracker(alert, mConfigKey);
     if (anomalyTracker != nullptr) {
         mAnomalyTrackers.push_back(anomalyTracker);
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index b822f2c..a7d07e3 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -21,6 +21,7 @@
 Landroid/app/ActivityManager;->isLowRamDeviceStatic()Z
 Landroid/app/ActivityManager;->isUserRunning(I)Z
 Landroid/app/ActivityManager;->mContext:Landroid/content/Context;
+Landroid/app/ActivityManagerNative;->asInterface(Landroid/os/IBinder;)Landroid/app/IActivityManager;
 Landroid/app/ActivityManagerNative;->getDefault()Landroid/app/IActivityManager;
 Landroid/app/ActivityManager;->PROCESS_STATE_TOP:I
 Landroid/app/ActivityManager$RecentTaskInfo;->firstActiveTime:J
@@ -40,6 +41,7 @@
 Landroid/app/Activity;->mWindow:Landroid/view/Window;
 Landroid/app/Activity;->mWindowManager:Landroid/view/WindowManager;
 Landroid/app/Activity;->setDisablePreviewScreenshots(Z)V
+Landroid/app/Activity;->setPersistent(Z)V
 Landroid/app/ActivityThread$ActivityClientRecord;->activityInfo:Landroid/content/pm/ActivityInfo;
 Landroid/app/ActivityThread$ActivityClientRecord;->activity:Landroid/app/Activity;
 Landroid/app/ActivityThread$ActivityClientRecord;->compatInfo:Landroid/content/res/CompatibilityInfo;
@@ -52,6 +54,7 @@
 Landroid/app/ActivityThread$AppBindData;->appInfo:Landroid/content/pm/ApplicationInfo;
 Landroid/app/ActivityThread$AppBindData;->info:Landroid/app/LoadedApk;
 Landroid/app/ActivityThread$AppBindData;->instrumentationArgs:Landroid/os/Bundle;
+Landroid/app/ActivityThread$AppBindData;->processName:Ljava/lang/String;
 Landroid/app/ActivityThread$AppBindData;->providers:Ljava/util/List;
 Landroid/app/ActivityThread$BindServiceData;->intent:Landroid/content/Intent;
 Landroid/app/ActivityThread$BindServiceData;->token:Landroid/os/IBinder;
@@ -87,15 +90,20 @@
 Landroid/app/ActivityThread;->mActivities:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mAllApplications:Ljava/util/ArrayList;
 Landroid/app/ActivityThread;->mBoundApplication:Landroid/app/ActivityThread$AppBindData;
+Landroid/app/ActivityThread;->mDensityCompatMode:Z
 Landroid/app/ActivityThread;->mH:Landroid/app/ActivityThread$H;
 Landroid/app/ActivityThread;->mInitialApplication:Landroid/app/Application;
 Landroid/app/ActivityThread;->mInstrumentation:Landroid/app/Instrumentation;
+Landroid/app/ActivityThread;->mLocalProvidersByName:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mNumVisibleActivities:I
 Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mServices:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->performNewIntents(Landroid/os/IBinder;Ljava/util/List;Z)V
 Landroid/app/ActivityThread;->performStopActivity(Landroid/os/IBinder;ZLjava/lang/String;)V
+Landroid/app/ActivityThread$ProviderClientRecord;->mHolder:Landroid/app/ContentProviderHolder;
 Landroid/app/ActivityThread$ProviderClientRecord;->mLocalProvider:Landroid/content/ContentProvider;
+Landroid/app/ActivityThread$ProviderClientRecord;->mProvider:Landroid/content/IContentProvider;
 Landroid/app/ActivityThread$ReceiverData;->compatInfo:Landroid/content/res/CompatibilityInfo;
 Landroid/app/ActivityThread$ReceiverData;->info:Landroid/content/pm/ActivityInfo;
 Landroid/app/ActivityThread$ReceiverData;->intent:Landroid/content/Intent;
@@ -104,6 +112,7 @@
 Landroid/app/ActivityThread$ServiceArgsData;->args:Landroid/content/Intent;
 Landroid/app/ActivityThread$ServiceArgsData;->token:Landroid/os/IBinder;
 Landroid/app/ActivityThread;->sPackageManager:Landroid/content/pm/IPackageManager;
+Landroid/app/ActivityThread;->startActivityNow(Landroid/app/Activity;Ljava/lang/String;Landroid/content/Intent;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;Landroid/os/Bundle;Landroid/app/Activity$NonConfigurationInstances;)Landroid/app/Activity;
 Landroid/app/admin/DevicePolicyManager;->getDeviceOwnerComponentOnAnyUser()Landroid/content/ComponentName;
 Landroid/app/admin/DevicePolicyManager;->getDeviceOwner()Ljava/lang/String;
 Landroid/app/admin/DevicePolicyManager;->getProfileOwner()Landroid/content/ComponentName;
@@ -143,6 +152,7 @@
 Landroid/app/ApplicationLoaders;->mLoaders:Landroid/util/ArrayMap;
 Landroid/app/Application;->mComponentCallbacks:Ljava/util/ArrayList;
 Landroid/app/Application;->mLoadedApk:Landroid/app/LoadedApk;
+Landroid/app/ApplicationPackageManager;->configurationChanged()V
 Landroid/app/ApplicationPackageManager;->deletePackage(Ljava/lang/String;Landroid/content/pm/IPackageDeleteObserver;I)V
 Landroid/app/ApplicationPackageManager;->getPackageSizeInfoAsUser(Ljava/lang/String;ILandroid/content/pm/IPackageStatsObserver;)V
 Landroid/app/ApplicationPackageManager;-><init>(Landroid/app/ContextImpl;Landroid/content/pm/IPackageManager;)V
@@ -200,11 +210,15 @@
 Landroid/app/backup/RestoreSession;->restoreAll(JLandroid/app/backup/RestoreObserver;)I
 Landroid/app/backup/RestoreSet;-><init>(Ljava/lang/String;Ljava/lang/String;J)V
 Landroid/app/backup/SelectBackupTransportCallback;-><init>()V
+Landroid/app/ContentProviderHolder;->info:Landroid/content/pm/ProviderInfo;
+Landroid/app/ContentProviderHolder;-><init>(Landroid/content/pm/ProviderInfo;)V
 Landroid/app/ContentProviderHolder;->provider:Landroid/content/IContentProvider;
 Landroid/app/ContextImpl;->createActivityContext(Landroid/app/ActivityThread;Landroid/app/LoadedApk;Landroid/content/pm/ActivityInfo;Landroid/os/IBinder;ILandroid/content/res/Configuration;)Landroid/app/ContextImpl;
 Landroid/app/ContextImpl;->getActivityToken()Landroid/os/IBinder;
 Landroid/app/ContextImpl;->getDisplay()Landroid/view/Display;
 Landroid/app/ContextImpl;->getPreferencesDir()Ljava/io/File;
+Landroid/app/ContextImpl;->getReceiverRestrictedContext()Landroid/content/Context;
+Landroid/app/ContextImpl;->mBasePackageName:Ljava/lang/String;
 Landroid/app/ContextImpl;->mContentResolver:Landroid/app/ContextImpl$ApplicationContentResolver;
 Landroid/app/ContextImpl;->mMainThread:Landroid/app/ActivityThread;
 Landroid/app/ContextImpl;->mOpPackageName:Ljava/lang/String;
@@ -216,6 +230,7 @@
 Landroid/app/ContextImpl;->mTheme:Landroid/content/res/Resources$Theme;
 Landroid/app/ContextImpl;->scheduleFinalCleanup(Ljava/lang/String;Ljava/lang/String;)V
 Landroid/app/ContextImpl;->setOuterContext(Landroid/content/Context;)V
+Landroid/app/ContextImpl;->sSharedPrefsCache:Landroid/util/ArrayMap;
 Landroid/app/DatePickerDialog;->mDatePicker:Landroid/widget/DatePicker;
 Landroid/app/Dialog;->CANCEL:I
 Landroid/app/Dialog;->dismissDialog()V
@@ -227,16 +242,23 @@
 Landroid/app/DownloadManager$Request;->mUri:Landroid/net/Uri;
 Landroid/app/FragmentManagerImpl;->mAdded:Ljava/util/ArrayList;
 Landroid/app/Fragment;->mChildFragmentManager:Landroid/app/FragmentManagerImpl;
+Landroid/app/IActivityManager;->bindService(Landroid/app/IApplicationThread;Landroid/os/IBinder;Landroid/content/Intent;Ljava/lang/String;Landroid/app/IServiceConnection;ILjava/lang/String;I)I
+Landroid/app/IActivityManager;->finishActivity(Landroid/os/IBinder;ILandroid/content/Intent;I)Z
+Landroid/app/IActivityManager;->finishReceiver(Landroid/os/IBinder;ILjava/lang/String;Landroid/os/Bundle;ZI)V
 Landroid/app/IActivityManager;->forceStopPackage(Ljava/lang/String;I)V
 Landroid/app/IActivityManager;->getLaunchedFromPackage(Landroid/os/IBinder;)Ljava/lang/String;
 Landroid/app/IActivityManager;->getTaskForActivity(Landroid/os/IBinder;Z)I
+Landroid/app/IActivityManager;->moveTaskToFront(IILandroid/os/Bundle;)V
+Landroid/app/IActivityManager;->publishContentProviders(Landroid/app/IApplicationThread;Ljava/util/List;)V
 Landroid/app/IActivityManager;->resumeAppSwitches()V
 Landroid/app/IActivityManager;->setRequestedOrientation(Landroid/os/IBinder;I)V
+Landroid/app/IActivityManager;->setTaskResizeable(II)V
 Landroid/app/IActivityManager$Stub$Proxy;->getConfiguration()Landroid/content/res/Configuration;
 Landroid/app/IActivityManager$Stub$Proxy;->getLaunchedFromUid(Landroid/os/IBinder;)I
 Landroid/app/IActivityManager$Stub$Proxy;->getProcessPss([I)[J
 Landroid/app/IActivityManager$Stub$Proxy;->isAppForeground(I)Z
 Landroid/app/IActivityManager$Stub$Proxy;->mRemote:Landroid/os/IBinder;
+Landroid/app/IActivityManager;->unbindService(Landroid/app/IServiceConnection;)Z
 Landroid/app/IAlarmManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/IAlarmManager$Stub;->TRANSACTION_remove:I
 Landroid/app/IAlarmManager$Stub;->TRANSACTION_set:I
@@ -256,6 +278,8 @@
 Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
 Landroid/app/job/IJobScheduler$Stub;->asInterface(Landroid/os/IBinder;)Landroid/app/job/IJobScheduler;
 Landroid/app/job/IJobScheduler$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/app/LoadedApk;->getClassLoader()Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->getDataDirFile()Ljava/io/File;
 Landroid/app/LoadedApk;->mActivityThread:Landroid/app/ActivityThread;
 Landroid/app/LoadedApk;->makeApplication(ZLandroid/app/Instrumentation;)Landroid/app/Application;
 Landroid/app/LoadedApk;->mAppDir:Ljava/lang/String;
@@ -263,7 +287,9 @@
 Landroid/app/LoadedApk;->mApplication:Landroid/app/Application;
 Landroid/app/LoadedApk;->mBaseClassLoader:Ljava/lang/ClassLoader;
 Landroid/app/LoadedApk;->mClassLoader:Ljava/lang/ClassLoader;
+Landroid/app/LoadedApk;->mDataDirFile:Ljava/io/File;
 Landroid/app/LoadedApk;->mDataDir:Ljava/lang/String;
+Landroid/app/LoadedApk;->mDisplayAdjustments:Landroid/view/DisplayAdjustments;
 Landroid/app/LoadedApk;->mPackageName:Ljava/lang/String;
 Landroid/app/LoadedApk;->mReceivers:Landroid/util/ArrayMap;
 Landroid/app/LoadedApk;->mResDir:Ljava/lang/String;
@@ -276,6 +302,7 @@
 Landroid/app/NativeActivity;->setWindowFormat(I)V
 Landroid/app/NativeActivity;->showIme(I)V
 Landroid/app/Notification$Builder;->mActions:Ljava/util/ArrayList;
+Landroid/app/Notification$Builder;->setChannel(Ljava/lang/String;)Landroid/app/Notification$Builder;
 Landroid/app/Notification;->EXTRA_SUBSTITUTE_APP_NAME:Ljava/lang/String;
 Landroid/app/Notification;->isGroupSummary()Z
 Landroid/app/NotificationManager;->getService()Landroid/app/INotificationManager;
@@ -310,6 +337,7 @@
 Landroid/app/StatusBarManager;->expandNotificationsPanel()V
 Landroid/app/StatusBarManager;->expandSettingsPanel(Ljava/lang/String;)V
 Landroid/app/StatusBarManager;->expandSettingsPanel()V
+Landroid/app/StatusBarManager;->getService()Lcom/android/internal/statusbar/IStatusBarService;
 Landroid/app/TimePickerDialog;->mTimePicker:Landroid/widget/TimePicker;
 Landroid/app/trust/ITrustManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/app/usage/UsageStatsManager;->getAppStandbyBuckets()Ljava/util/Map;
@@ -361,6 +389,8 @@
 Landroid/content/AsyncTaskLoader;->mExecutor:Ljava/util/concurrent/Executor;
 Landroid/content/BroadcastReceiver$PendingResult;-><init>(ILjava/lang/String;Landroid/os/Bundle;IZZLandroid/os/IBinder;II)V
 Landroid/content/BroadcastReceiver;->setPendingResult(Landroid/content/BroadcastReceiver$PendingResult;)V
+Landroid/content/ContentProviderClient;->mContentProvider:Landroid/content/IContentProvider;
+Landroid/content/ContentProviderClient;->mPackageName:Ljava/lang/String;
 Landroid/content/ContentProvider;->mContext:Landroid/content/Context;
 Landroid/content/ContentProvider;->mPathPermissions:[Landroid/content/pm/PathPermission;
 Landroid/content/ContentProvider;->mReadPermission:Ljava/lang/String;
@@ -394,9 +424,11 @@
 Landroid/content/CursorLoader;->mCancellationSignal:Landroid/os/CancellationSignal;
 Landroid/content/CursorLoader;->mObserver:Landroid/content/Loader$ForceLoadContentObserver;
 Landroid/content/IClipboard$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IClipboard;
+Landroid/content/IContentProvider;->call(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Landroid/os/Bundle;)Landroid/os/Bundle;
 Landroid/content/IContentService;->cancelSync(Landroid/accounts/Account;Ljava/lang/String;Landroid/content/ComponentName;)V
 Landroid/content/IContentService;->getMasterSyncAutomatically()Z
 Landroid/content/IContentService;->setMasterSyncAutomatically(Z)V
+Landroid/content/IContentService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/IContentService;
 Landroid/content/IContentService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/Intent;->ACTION_ALARM_CHANGED:Ljava/lang/String;
 Landroid/content/IntentFilter;->mActions:Ljava/util/ArrayList;
@@ -429,6 +461,7 @@
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getPackagesForUid(I)[Ljava/lang/String;
 Landroid/content/pm/IPackageManager$Stub$Proxy;->getSystemSharedLibraryNames()[Ljava/lang/String;
 Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
+Landroid/content/pm/LauncherActivityInfo;->mActivityInfo:Landroid/content/pm/ActivityInfo;
 Landroid/content/pm/LauncherApps;->mPm:Landroid/content/pm/PackageManager;
 Landroid/content/pm/LauncherApps;->startShortcut(Ljava/lang/String;Ljava/lang/String;Landroid/graphics/Rect;Landroid/os/Bundle;I)V
 Landroid/content/pm/PackageInstaller$SessionParams;->setAllocateAggressive(Z)V
@@ -570,6 +603,7 @@
 Landroid/content/SyncStatusInfo;->lastSuccessTime:J
 Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
 Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
+Landroid/database/AbstractCursor;->mRowIdColumnIndex:I
 Landroid/database/CursorWindow;->mWindowPtr:J
 Landroid/database/CursorWindow;->sCursorWindowSize:I
 Landroid/database/CursorWindow;->sWindowToPidMap:Landroid/util/LongSparseArray;
@@ -1100,6 +1134,7 @@
 Landroid/net/wifi/WifiEnterpriseConfig;->getCaCertificateAlias()Ljava/lang/String;
 Landroid/net/wifi/WifiEnterpriseConfig;->getClientCertificateAlias()Ljava/lang/String;
 Landroid/net/wifi/WifiInfo;->getMeteredHint()Z
+Landroid/net/wifi/WifiInfo;->mMacAddress:Ljava/lang/String;
 Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V
 Landroid/net/wifi/WifiManager;->connect(ILandroid/net/wifi/WifiManager$ActionListener;)V
 Landroid/net/wifi/WifiManager;->connect(Landroid/net/wifi/WifiConfiguration;Landroid/net/wifi/WifiManager$ActionListener;)V
@@ -1513,6 +1548,13 @@
 Landroid/telephony/SignalStrength;->getLteRsrq()I
 Landroid/telephony/SignalStrength;->getLteRssnr()I
 Landroid/telephony/SignalStrength;->getLteSignalStrength()I
+Landroid/telephony/SignalStrength;->mGsmBitErrorRate:I
+Landroid/telephony/SignalStrength;->mGsmSignalStrength:I
+Landroid/telephony/SignalStrength;->mLteCqi:I
+Landroid/telephony/SignalStrength;->mLteRsrp:I
+Landroid/telephony/SignalStrength;->mLteRsrq:I
+Landroid/telephony/SignalStrength;->mLteRssnr:I
+Landroid/telephony/SignalStrength;->mLteSignalStrength:I
 Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GOOD:I
 Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_GREAT:I
 Landroid/telephony/SignalStrength;->SIGNAL_STRENGTH_MODERATE:I
@@ -1564,6 +1606,7 @@
 Landroid/telephony/TelephonyManager;-><init>()V
 Landroid/telephony/TelephonyManager;->isMultiSimEnabled()Z
 Landroid/telephony/TelephonyManager;->isNetworkRoaming(I)Z
+Landroid/telephony/TelephonyManager;->isVolteAvailable()Z
 Landroid/telephony/TelephonyManager;->setDataEnabled(IZ)V
 Landroid/text/AndroidBidi;->bidi(I[C[B)I
 Landroid/text/DynamicLayout;-><init>(Ljava/lang/CharSequence;Ljava/lang/CharSequence;Landroid/text/TextPaint;ILandroid/text/Layout$Alignment;Landroid/text/TextDirectionHeuristic;FFZIIILandroid/text/TextUtils$TruncateAt;I)V
@@ -1650,6 +1693,7 @@
 Landroid/view/Choreographer;->removeCallbacks(ILjava/lang/Runnable;Ljava/lang/Object;)V
 Landroid/view/Choreographer;->scheduleVsyncLocked()V
 Landroid/view/Choreographer;->USE_VSYNC:Z
+Landroid/view/ContextThemeWrapper;->getThemeResId()I
 Landroid/view/ContextThemeWrapper;->mResources:Landroid/content/res/Resources;
 Landroid/view/ContextThemeWrapper;->mTheme:Landroid/content/res/Resources$Theme;
 Landroid/view/ContextThemeWrapper;->mThemeResource:I
@@ -1675,6 +1719,7 @@
 Landroid/view/InputEventReceiver;->dispatchBatchedInputEventPending()V
 Landroid/view/InputEventReceiver;->dispatchInputEvent(ILandroid/view/InputEvent;I)V
 Landroid/view/InputEventSender;->dispatchInputEventFinished(IZ)V
+Landroid/view/inputmethod/InputMethodInfo;->mSubtypes:Landroid/view/inputmethod/InputMethodSubtypeArray;
 Landroid/view/inputmethod/InputMethodManager;->finishInputLocked()V
 Landroid/view/inputmethod/InputMethodManager;->focusIn(Landroid/view/View;)V
 Landroid/view/inputmethod/InputMethodManager;->getInputMethodWindowVisibleHeight()I
@@ -1688,6 +1733,7 @@
 Landroid/view/inputmethod/InputMethodManager;->showSoftInputUnchecked(ILandroid/os/ResultReceiver;)V
 Landroid/view/inputmethod/InputMethodManager;->sInstance:Landroid/view/inputmethod/InputMethodManager;
 Landroid/view/inputmethod/InputMethodManager;->windowDismissed(Landroid/os/IBinder;)V
+Landroid/view/inputmethod/InputMethodSubtypeArray;-><init>(Ljava/util/List;)V
 Landroid/view/InputQueue;->finishInputEvent(JZ)V
 Landroid/view/IWindowManager;->getAnimationScale(I)F
 Landroid/view/IWindowManager;->hasNavigationBar()Z
@@ -1881,6 +1927,7 @@
 Landroid/view/WindowManagerGlobal;->getRootView(Ljava/lang/String;)Landroid/view/View;
 Landroid/view/WindowManagerGlobal;->getViewRootNames()[Ljava/lang/String;
 Landroid/view/WindowManagerGlobal;->getWindowManagerService()Landroid/view/IWindowManager;
+Landroid/view/WindowManagerGlobal;->initialize()V
 Landroid/view/WindowManagerGlobal;->mLock:Ljava/lang/Object;
 Landroid/view/WindowManagerGlobal;->mParams:Ljava/util/ArrayList;
 Landroid/view/WindowManagerGlobal;->mRoots:Ljava/util/ArrayList;
@@ -2087,6 +2134,7 @@
 Landroid/widget/PopupWindow;->mLastWidth:I
 Landroid/widget/PopupWindow;->mOnScrollChangedListener:Landroid/view/ViewTreeObserver$OnScrollChangedListener;
 Landroid/widget/PopupWindow;->mOverlapAnchor:Z
+Landroid/widget/PopupWindow;->mTouchInterceptor:Landroid/view/View$OnTouchListener;
 Landroid/widget/PopupWindow;->mWidthMode:I
 Landroid/widget/PopupWindow;->mWindowLayoutType:I
 Landroid/widget/PopupWindow;->preparePopup(Landroid/view/WindowManager$LayoutParams;)V
@@ -2109,10 +2157,14 @@
 Landroid/widget/RemoteViews$Action;->mergeBehavior()I
 Landroid/widget/RemoteViews$Action;->viewId:I
 Landroid/widget/RemoteViews$BitmapCache;->mBitmaps:Ljava/util/ArrayList;
+Landroid/widget/RemoteViews$BitmapReflectionAction;->bitmap:Landroid/graphics/Bitmap;
+Landroid/widget/RemoteViews$BitmapReflectionAction;->methodName:Ljava/lang/String;
+Landroid/widget/RemoteViews;->estimateMemoryUsage()I
 Landroid/widget/RemoteViews;->mActions:Ljava/util/ArrayList;
 Landroid/widget/RemoteViews;->mApplication:Landroid/content/pm/ApplicationInfo;
 Landroid/widget/RemoteViews;->mBitmapCache:Landroid/widget/RemoteViews$BitmapCache;
 Landroid/widget/RemoteViews;->mergeRemoteViews(Landroid/widget/RemoteViews;)V
+Landroid/widget/RemoteViews;->mPortrait:Landroid/widget/RemoteViews;
 Landroid/widget/RemoteViews$ReflectionAction;->methodName:Ljava/lang/String;
 Landroid/widget/ScrollBarDrawable;->mVerticalThumb:Landroid/graphics/drawable/Drawable;
 Landroid/widget/ScrollBarDrawable;->setHorizontalThumbDrawable(Landroid/graphics/drawable/Drawable;)V
@@ -2145,6 +2197,7 @@
 Landroid/widget/TextView;->mMaximum:I
 Landroid/widget/TextView;->mMaxMode:I
 Landroid/widget/TextView;->mSingleLine:Z
+Landroid/widget/TextView;->mTextPaint:Landroid/text/TextPaint;
 Landroid/widget/TextView;->setText(Ljava/lang/CharSequence;Landroid/widget/TextView$BufferType;ZI)V
 Landroid/widget/Toast;->getService()Landroid/app/INotificationManager;
 Landroid/widget/Toast;->sService:Landroid/app/INotificationManager;
@@ -2154,6 +2207,7 @@
 Landroid/widget/VideoView;->mUri:Landroid/net/Uri;
 Landroid/widget/VideoView;->mVideoHeight:I
 Landroid/widget/VideoView;->mVideoWidth:I
+Lcom/android/internal/app/IAppOpsService$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/app/IAppOpsService;
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/app/IBatteryStats;->getStatistics()[B
@@ -2244,6 +2298,13 @@
 Lcom/android/internal/R$integer;->config_screenBrightnessDim:I
 Lcom/android/internal/R$integer;->config_toastDefaultGravity:I
 Lcom/android/internal/R$layout;->screen_title:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountPreferences:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_accountType:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_customTokens:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator:[I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_icon:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_label:I
+Lcom/android/internal/R$styleable;->AccountAuthenticator_smallIcon:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication_enabled:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication_hardwareAccelerated:I
 Lcom/android/internal/R$styleable;->AndroidManifestApplication:[I
@@ -2274,6 +2335,14 @@
 Lcom/android/internal/R$styleable;->ImageView_src:I
 Lcom/android/internal/R$styleable;->ScrollView_fillViewport:I
 Lcom/android/internal/R$styleable;->ScrollView:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_accountType:I
+Lcom/android/internal/R$styleable;->SyncAdapter_allowParallelSyncs:I
+Lcom/android/internal/R$styleable;->SyncAdapter_contentAuthority:I
+Lcom/android/internal/R$styleable;->SyncAdapter:[I
+Lcom/android/internal/R$styleable;->SyncAdapter_isAlwaysSyncable:I
+Lcom/android/internal/R$styleable;->SyncAdapter_settingsActivity:I
+Lcom/android/internal/R$styleable;->SyncAdapter_supportsUploading:I
+Lcom/android/internal/R$styleable;->SyncAdapter_userVisible:I
 Lcom/android/internal/R$styleable;->TabWidget:[I
 Lcom/android/internal/R$styleable;->TextView_drawableBottom:I
 Lcom/android/internal/R$styleable;->TextView_drawableLeft:I
@@ -2289,7 +2358,11 @@
 Lcom/android/internal/R$styleable;->ViewStub:[I
 Lcom/android/internal/R$styleable;->ViewStub_inflatedId:I
 Lcom/android/internal/R$styleable;->ViewStub_layout:I
+Lcom/android/internal/R$styleable;->Window:[I
 Lcom/android/internal/R$styleable;->Window_windowActionBarFullscreenDecorLayout:I
+Lcom/android/internal/R$styleable;->Window_windowIsFloating:I
+Lcom/android/internal/R$styleable;->Window_windowIsTranslucent:I
+Lcom/android/internal/R$styleable;->Window_windowShowWallpaper:I
 Lcom/android/internal/R$style;->Theme:I
 Lcom/android/internal/R$xml;->power_profile:I
 Lcom/android/internal/telephony/IPhoneSubInfo$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/IPhoneSubInfo;
@@ -2339,6 +2412,7 @@
 Ldalvik/system/CloseGuard;->get()Ldalvik/system/CloseGuard;
 Ldalvik/system/CloseGuard;->open(Ljava/lang/String;)V
 Ldalvik/system/CloseGuard;->warnIfOpen()V
+Ldalvik/system/DexFile;->getClassNameList(Ljava/lang/Object;)[Ljava/lang/String;
 Ldalvik/system/DexFile;->loadClassBinaryName(Ljava/lang/String;Ljava/lang/ClassLoader;Ljava/util/List;)Ljava/lang/Class;
 Ldalvik/system/DexFile;->mCookie:Ljava/lang/Object;
 Ldalvik/system/DexFile;->mFileName:Ljava/lang/String;
@@ -2350,10 +2424,12 @@
 Ldalvik/system/DexPathList$Element;-><init>(Ljava/io/File;ZLjava/io/File;Ldalvik/system/DexFile;)V
 Ldalvik/system/DexPathList;-><init>(Ljava/lang/ClassLoader;Ljava/lang/String;Ljava/lang/String;Ljava/io/File;)V
 Ldalvik/system/DexPathList;->makeDexElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;Ljava/lang/ClassLoader;)[Ldalvik/system/DexPathList$Element;
+Ldalvik/system/DexPathList;->makeInMemoryDexElements([Ljava/nio/ByteBuffer;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
 Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;)[Ldalvik/system/DexPathList$NativeLibraryElement;
 Ldalvik/system/DexPathList;->makePathElements(Ljava/util/List;Ljava/io/File;Ljava/util/List;)[Ldalvik/system/DexPathList$Element;
 Ldalvik/system/DexPathList;->nativeLibraryDirectories:Ljava/util/List;
 Ldalvik/system/DexPathList$NativeLibraryElement;-><init>(Ljava/io/File;)V
+Ldalvik/system/DexPathList$NativeLibraryElement;->path:Ljava/io/File;
 Ldalvik/system/DexPathList;->nativeLibraryPathElements:[Ldalvik/system/DexPathList$NativeLibraryElement;
 Ldalvik/system/DexPathList;->splitPaths(Ljava/lang/String;Z)Ljava/util/List;
 Ldalvik/system/DexPathList;->systemNativeLibraryDirectories:Ljava/util/List;
@@ -2369,6 +2445,7 @@
 Ldalvik/system/VMRuntime;->runFinalization(J)V
 Ldalvik/system/VMRuntime;->setMinimumHeapSize(J)J
 Ldalvik/system/VMRuntime;->setTargetHeapUtilization(F)F
+Ldalvik/system/VMRuntime;->setTargetSdkVersion(I)V
 Ldalvik/system/VMRuntime;->trackExternalAllocation(J)Z
 Ldalvik/system/VMRuntime;->trackExternalFree(J)V
 Ldalvik/system/VMRuntime;->vmInstructionSet()Ljava/lang/String;
@@ -2620,8 +2697,10 @@
 Ljava/util/concurrent/ThreadLocalRandom;->writeObject(Ljava/io/ObjectOutputStream;)V
 Ljava/util/Date;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/Date;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumMap;->keyType:Ljava/lang/Class;
 Ljava/util/EnumMap;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/EnumMap;->writeObject(Ljava/io/ObjectOutputStream;)V
+Ljava/util/EnumSet;->elementType:Ljava/lang/Class;
 Ljava/util/EnumSet;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/GregorianCalendar;->readObject(Ljava/io/ObjectInputStream;)V
 Ljava/util/HashMap$HashIterator;->hasNext()Z
diff --git a/core/java/android/annotation/OWNERS b/core/java/android/annotation/OWNERS
new file mode 100644
index 0000000..d6bb71b
--- /dev/null
+++ b/core/java/android/annotation/OWNERS
@@ -0,0 +1 @@
+tnorbye@google.com
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 6c3d248..8a9efe8 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
+
 import static java.lang.Character.MIN_VALUE;
 
 import android.annotation.CallSuper;
@@ -135,6 +136,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 
@@ -1898,7 +1900,7 @@
 
         if (isFinishing()) {
             if (mAutoFillResetNeeded) {
-                getAutofillManager().onActivityFinished();
+                getAutofillManager().onActivityFinishing();
             } else if (mIntent != null
                     && mIntent.hasExtra(AutofillManager.EXTRA_RESTORE_SESSION_TOKEN)) {
                 // Activity was launched when user tapped a link in the Autofill Save UI - since
@@ -7689,6 +7691,9 @@
                 }
             }
         }
+        if (android.view.autofill.Helper.sVerbose) {
+            Log.v(TAG, "autofillClientGetViewVisibility(): " + Arrays.toString(visible));
+        }
         return visible;
     }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 4c9fb74..1026550 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -543,7 +543,6 @@
             OP_CAMERA,
             // Body sensors
             OP_BODY_SENSORS,
-            OP_REQUEST_DELETE_PACKAGES,
 
             // APPOP PERMISSIONS
             OP_ACCESS_NOTIFICATIONS,
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index a788989..b072ee6 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -1000,7 +1000,7 @@
      */
     @Override
     public boolean isAutofillCompatibilityEnabled() {
-        return mBase.isAutofillCompatibilityEnabled();
+        return mBase != null && mBase.isAutofillCompatibilityEnabled();
     }
 
     /**
@@ -1008,6 +1008,8 @@
      */
     @Override
     public void setAutofillCompatibilityEnabled(boolean  autofillCompatEnabled) {
-        mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
+        if (mBase != null) {
+            mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
+        }
     }
 }
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index cf01451..424fa83 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -27,9 +27,11 @@
 import android.annotation.StyleableRes;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ActivityInfo.Config;
+import android.content.res.AssetManager.AssetInputStream;
 import android.content.res.Configuration.NativeConfig;
 import android.content.res.Resources.NotFoundException;
 import android.graphics.Bitmap;
+import android.graphics.ImageDecoder;
 import android.graphics.Typeface;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -752,6 +754,26 @@
     }
 
     /**
+     * Loads a Drawable from an encoded image stream, or null.
+     *
+     * This call will handle closing ais.
+     */
+    private Drawable decodeImageDrawable(@NonNull AssetInputStream ais,
+            @NonNull Resources wrapper, @NonNull TypedValue value) {
+        ImageDecoder.Source src = new ImageDecoder.AssetInputStreamSource(ais,
+                            wrapper, value);
+        try {
+            return ImageDecoder.decodeDrawable(src, (decoder, info, s) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (IOException ioe) {
+            // This is okay. This may be something that ImageDecoder does not
+            // support, like SVG.
+            return null;
+        }
+    }
+
+    /**
      * Loads a drawable from XML or resources stream.
      */
     @NonNull
@@ -811,8 +833,8 @@
                 } else {
                     final InputStream is = mAssets.openNonAsset(
                             value.assetCookie, file, AssetManager.ACCESS_STREAMING);
-                    dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
-                    is.close();
+                    AssetInputStream ais = (AssetInputStream) is;
+                    dr = decodeImageDrawable(ais, wrapper, value);
                 }
             } finally {
                 stack.pop();
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index 931b5c9..f08e1cc 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -242,6 +242,9 @@
 
     /**
      * Returns the number of physical cameras available on this device.
+     * The return value of this method might change dynamically if the device
+     * supports external cameras and an external camera is connected or
+     * disconnected.
      *
      * @return total number of accessible camera devices, or 0 if there are no
      *   cameras or an error was encountered enumerating them.
@@ -3542,8 +3545,8 @@
         /**
          * Gets the horizontal angle of view in degrees.
          *
-         * @return horizontal angle of view. This method will always return a
-         *         valid value.
+         * @return horizontal angle of view. Returns -1.0 when the device
+         *         doesn't report view angle information.
          */
         public float getHorizontalViewAngle() {
             return Float.parseFloat(get(KEY_HORIZONTAL_VIEW_ANGLE));
@@ -3552,8 +3555,8 @@
         /**
          * Gets the vertical angle of view in degrees.
          *
-         * @return vertical angle of view. This method will always return a
-         *         valid value.
+         * @return vertical angle of view. Returns -1.0 when the device
+         *         doesn't report view angle information.
          */
         public float getVerticalViewAngle() {
             return Float.parseFloat(get(KEY_VERTICAL_VIEW_ANGLE));
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 732f6a5..e558b7e 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -829,19 +829,24 @@
      * <li>{@link CameraCharacteristics#LENS_RADIAL_DISTORTION android.lens.radialDistortion}</li>
      * </ul>
      * </li>
+     * <li>The SENSOR_INFO_TIMESTAMP_SOURCE of the logical device and physical devices must be
+     *   the same.</li>
      * <li>The logical camera device must be LIMITED or higher device.</li>
      * </ul>
      * <p>Both the logical camera device and its underlying physical devices support the
      * mandatory stream combinations required for their device levels.</p>
      * <p>Additionally, for each guaranteed stream combination, the logical camera supports:</p>
      * <ul>
-     * <li>Replacing one logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
+     * <li>For each guaranteed stream combination, the logical camera supports replacing one
+     *   logical {@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}
      *   or raw stream with two physical streams of the same size and format, each from a
      *   separate physical camera, given that the size and format are supported by both
      *   physical cameras.</li>
-     * <li>Adding two raw streams, each from one physical camera, if the logical camera doesn't
-     *   advertise RAW capability, but the underlying physical cameras do. This is usually
-     *   the case when the physical cameras have different sensor sizes.</li>
+     * <li>If the logical camera doesn't advertise RAW capability, but the underlying physical
+     *   cameras do, the logical camera will support guaranteed stream combinations for RAW
+     *   capability, except that the RAW streams will be physical streams, each from a separate
+     *   physical camera. This is usually the case when the physical cameras have different
+     *   sensor sizes.</li>
      * </ul>
      * <p>Using physical streams in place of a logical stream of the same size and format will
      * not slow down the frame rate of the capture, as long as the minimum frame duration
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index b205e2c..a040a09 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -82,11 +82,9 @@
  *
  * </ul>
  *
- * <p>Please note that surface sharing is currently only enabled for outputs that use the
- * {@link ImageFormat#PRIVATE} format. This includes surface sources like
- * {@link android.view.SurfaceView}, {@link android.media.MediaRecorder},
- * {@link android.graphics.SurfaceTexture} and {@link android.media.ImageReader}, configured using
- * the aforementioned format.</p>
+ * <p> As of {@link android.os.Build.VERSION_CODES#P Android P}, all formats can be used for
+ * sharing, subject to device support. On prior API levels, only {@link ImageFormat#PRIVATE}
+ * format may be used.</p>
  *
  * @see CameraDevice#createCaptureSessionByOutputConfigurations
  *
diff --git a/core/java/android/hardware/usb/UsbDeviceConnection.java b/core/java/android/hardware/usb/UsbDeviceConnection.java
index 5b15c0d..9e5174a 100644
--- a/core/java/android/hardware/usb/UsbDeviceConnection.java
+++ b/core/java/android/hardware/usb/UsbDeviceConnection.java
@@ -222,7 +222,10 @@
      * @param endpoint the endpoint for this transaction
      * @param buffer buffer for data to send or receive; can be {@code null} to wait for next
      *               transaction without reading data
-     * @param length the length of the data to send or receive
+     * @param length the length of the data to send or receive. Before
+     *               {@value Build.VERSION_CODES#P}, a value larger than 16384 bytes
+     *               would be truncated down to 16384. In API {@value Build.VERSION_CODES#P}
+     *               and after, any value of length is valid.
      * @param timeout in milliseconds, 0 is infinite
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
@@ -239,7 +242,10 @@
      * @param endpoint the endpoint for this transaction
      * @param buffer buffer for data to send or receive
      * @param offset the index of the first byte in the buffer to send or receive
-     * @param length the length of the data to send or receive
+     * @param length the length of the data to send or receive. Before
+     *               {@value Build.VERSION_CODES#P}, a value larger than 16384 bytes
+     *               would be truncated down to 16384. In API {@value Build.VERSION_CODES#P}
+     *               and after, any value of length is valid.
      * @param timeout in milliseconds, 0 is infinite
      * @return length of data transferred (or zero) for success,
      * or negative value for failure
@@ -247,6 +253,10 @@
     public int bulkTransfer(UsbEndpoint endpoint,
             byte[] buffer, int offset, int length, int timeout) {
         checkBounds(buffer, offset, length);
+        if (mContext.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+                && length > UsbRequest.MAX_USBFS_BUFFER_SIZE) {
+            length = UsbRequest.MAX_USBFS_BUFFER_SIZE;
+        }
         return native_bulk_request(endpoint.getAddress(), buffer, offset, length, timeout);
     }
 
diff --git a/core/java/android/hardware/usb/UsbRequest.java b/core/java/android/hardware/usb/UsbRequest.java
index 2e8f8e1..f59c87e 100644
--- a/core/java/android/hardware/usb/UsbRequest.java
+++ b/core/java/android/hardware/usb/UsbRequest.java
@@ -17,6 +17,7 @@
 package android.hardware.usb;
 
 import android.annotation.Nullable;
+import android.os.Build;
 import android.util.Log;
 
 import com.android.internal.util.Preconditions;
@@ -43,7 +44,7 @@
     private static final String TAG = "UsbRequest";
 
     // From drivers/usb/core/devio.c
-    private static final int MAX_USBFS_BUFFER_SIZE = 16384;
+    static final int MAX_USBFS_BUFFER_SIZE = 16384;
 
     // used by the JNI code
     private long mNativeContext;
@@ -175,7 +176,9 @@
      *               capacity will be ignored. Once the request
      *               {@link UsbDeviceConnection#requestWait() is processed} the position will be set
      *               to the number of bytes read/written.
-     * @param length number of bytes to read or write.
+     * @param length number of bytes to read or write. Before {@value Build.VERSION_CODES#P}, a
+     *               value larger than 16384 bytes would be truncated down to 16384. In API
+     *               {@value Build.VERSION_CODES#P} and after, any value of length is valid.
      *
      * @return true if the queueing operation succeeded
      *
@@ -186,6 +189,11 @@
         boolean out = (mEndpoint.getDirection() == UsbConstants.USB_DIR_OUT);
         boolean result;
 
+        if (mConnection.getContext().getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.P
+                && length > MAX_USBFS_BUFFER_SIZE) {
+            length = MAX_USBFS_BUFFER_SIZE;
+        }
+
         synchronized (mLock) {
             // save our buffer for when the request has completed
             mBuffer = buffer;
@@ -222,7 +230,10 @@
      *               of the buffer is undefined until the request is returned by
      *               {@link UsbDeviceConnection#requestWait}. If the request failed the buffer
      *               will be unchanged; if the request succeeded the position of the buffer is
-     *               incremented by the number of bytes sent/received.
+     *               incremented by the number of bytes sent/received. Before
+     *               {@value Build.VERSION_CODES#P}, a buffer of length larger than 16384 bytes
+     *               would throw IllegalArgumentException. In API {@value Build.VERSION_CODES#P}
+     *               and after, any size buffer is valid.
      *
      * @return true if the queueing operation succeeded
      */
@@ -244,9 +255,12 @@
                 mIsUsingNewQueue = true;
                 wasQueued = native_queue(null, 0, 0);
             } else {
-                // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
-                Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
-                        "number of remaining bytes");
+                if (mConnection.getContext().getApplicationInfo().targetSdkVersion
+                        < Build.VERSION_CODES.P) {
+                    // Can only send/receive MAX_USBFS_BUFFER_SIZE bytes at once
+                    Preconditions.checkArgumentInRange(buffer.remaining(), 0, MAX_USBFS_BUFFER_SIZE,
+                            "number of remaining bytes");
+                }
 
                 // Can not receive into read-only buffers.
                 Preconditions.checkArgument(!(buffer.isReadOnly() && !isSend), "buffer can not be "
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 7dde2ed..91c99be 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2662,7 +2662,7 @@
      * A {@code NetworkCallback} is registered by calling
      * {@link #requestNetwork(NetworkRequest, NetworkCallback)},
      * {@link #registerNetworkCallback(NetworkRequest, NetworkCallback)},
-     * or {@link #registerDefaultNetworkCallback(NetworkCallback). A {@code NetworkCallback} is
+     * or {@link #registerDefaultNetworkCallback(NetworkCallback)}. A {@code NetworkCallback} is
      * unregistered by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
      * A {@code NetworkCallback} should be registered at most once at any time.
      * A {@code NetworkCallback} that has been unregistered can be registered again.
diff --git a/core/java/android/os/storage/StorageResultCode.java b/core/java/android/os/storage/StorageResultCode.java
deleted file mode 100644
index c843887..0000000
--- a/core/java/android/os/storage/StorageResultCode.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2007 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.storage;
-
-/**
- * Class that provides access to constants returned from StorageManager
- * and lower level StorageManagerService APIs.
- * 
- * @hide
- */
-public class StorageResultCode
-{
-    /**
-     * Operation succeeded.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationSucceeded               =  0;
-
-    /**
-     * Operation failed: Internal error.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationFailedInternalError     = -1;
-
-    /**
-     * Operation failed: Missing media.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationFailedNoMedia           = -2;
-
-    /**
-     * Operation failed: Media is blank.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationFailedMediaBlank        = -3;
-
-    /**
-     * Operation failed: Media is corrupt.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationFailedMediaCorrupt      = -4;
-
-    /**
-     * Operation failed: Storage not mounted.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationFailedStorageNotMounted  = -5;
-
-    /**
-     * Operation failed: Storage is mounted.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationFailedStorageMounted     = -6;
-
-    /**
-     * Operation failed: Storage is busy.
-     * @see android.os.storage.StorageManager
-     */
-    public static final int OperationFailedStorageBusy        = -7;
-
-}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 05ab486..598eeef 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3692,18 +3692,15 @@
                 new SettingsValidators.InclusiveIntegerRangeValidator(0, 3);
 
         /**
-         * User-selected RTT mode
+         * User-selected RTT mode. When on, outgoing and incoming calls will be answered as RTT
+         * calls when supported by the device and carrier. Boolean value.
          * 0 = OFF
-         * 1 = FULL
-         * 2 = VCO
-         * 3 = HCO
-         * Uses the same constants as TTY (e.g. {@link android.telecom.TelecomManager#TTY_MODE_OFF})
-         * @hide
+         * 1 = ON
          */
         public static final String RTT_CALLING_MODE = "rtt_calling_mode";
 
         /** @hide */
-        public static final Validator RTT_CALLING_MODE_VALIDATOR = TTY_MODE_VALIDATOR;
+        public static final Validator RTT_CALLING_MODE_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
          * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is
@@ -10460,6 +10457,9 @@
          * <pre>
          * smart_selection_dark_launch              (boolean)
          * smart_selection_enabled_for_edit_text    (boolean)
+         * suggest_selection_max_range_length       (int)
+         * classify_text_max_range_length           (int)
+         * generate_links_max_text_length           (int)
          * </pre>
          *
          * <p>
diff --git a/core/java/android/provider/SettingsSlicesContract.java b/core/java/android/provider/SettingsSlicesContract.java
index f79d852..7dc9488 100644
--- a/core/java/android/provider/SettingsSlicesContract.java
+++ b/core/java/android/provider/SettingsSlicesContract.java
@@ -31,12 +31,12 @@
  * <p>
  * {@link Uri} builder example:
  * <pre>
- * Uri wifiActionUri = AUTHORITY_URI
+ * Uri wifiActionUri = BASE_URI
  *         .buildUpon()
  *         .appendPath(PATH_SETTING_ACTION)
  *         .appendPath(KEY_WIFI)
  *         .build();
- * Uri bluetoothIntentUri = AUTHORITY_URI
+ * Uri bluetoothIntentUri = BASE_URI
  *         .buildUpon()
  *         .appendPath(PATH_SETTING_INTENT)
  *         .appendPath(KEY_BLUETOOTH)
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index 1d13335..f4dcce1 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -75,6 +75,7 @@
     public static final int KM_TAG_ALLOW_WHILE_ON_BODY = KM_BOOL | 506;
     public static final int KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED = KM_BOOL | 507;
     public static final int KM_TAG_TRUSTED_CONFIRMATION_REQUIRED = KM_BOOL | 508;
+    public static final int KM_TAG_UNLOCKED_DEVICE_REQUIRED = KM_BOOL | 509;
 
     public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600;
     public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601;
@@ -216,6 +217,7 @@
     public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
     public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
     public static final int KM_ERROR_CANNOT_ATTEST_IDS = -66;
+    public static final int KM_ERROR_DEVICE_LOCKED = -72;
     public static final int KM_ERROR_UNIMPLEMENTED = -100;
     public static final int KM_ERROR_VERSION_MISMATCH = -101;
     public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -262,6 +264,7 @@
         sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
                 "Invalid MAC or authentication tag length");
         sErrorCodeToString.put(KM_ERROR_CANNOT_ATTEST_IDS, "Unable to attest device ids");
+        sErrorCodeToString.put(KM_ERROR_DEVICE_LOCKED, "Device locked");
         sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
         sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
     }
diff --git a/core/java/android/text/OWNERS b/core/java/android/text/OWNERS
index 9f2182e..e561371 100644
--- a/core/java/android/text/OWNERS
+++ b/core/java/android/text/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
 siyamed@google.com
 nona@google.com
 clarabayarri@google.com
diff --git a/core/java/android/text/style/TypefaceSpan.java b/core/java/android/text/style/TypefaceSpan.java
index 1622812..908de29 100644
--- a/core/java/android/text/style/TypefaceSpan.java
+++ b/core/java/android/text/style/TypefaceSpan.java
@@ -17,6 +17,8 @@
 package android.text.style;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.graphics.LeakyTypefaceStorage;
 import android.graphics.Paint;
 import android.graphics.Typeface;
 import android.os.Parcel;
@@ -25,33 +27,69 @@
 import android.text.TextUtils;
 
 /**
- * Changes the typeface family of the text to which the span is attached. Examples of typeface
- * family include "monospace", "serif", and "sans-serif".
+ * Span that updates the typeface of the text it's attached to. The <code>TypefaceSpan</code> can
+ * be constructed either based on a font family or based on a <code>Typeface</code>. When
+ * {@link #TypefaceSpan(String)} is used, the previous style of the <code>TextView</code> is kept.
+ * When {@link #TypefaceSpan(Typeface)} is used, the <code>Typeface</code> style replaces the
+ * <code>TextView</code>'s style.
  * <p>
- * For example, change the typeface of a text to "monospace" like this:
+ * For example, let's consider a <code>TextView</code> with
+ * <code>android:textStyle="italic"</code> and a typeface created based on a font from resources,
+ * with a bold style. When applying a <code>TypefaceSpan</code> based the typeface, the text will
+ * only keep the bold style, overriding the <code>TextView</code>'s textStyle. When applying a
+ * <code>TypefaceSpan</code> based on a font family: "monospace", the resulted text will keep the
+ * italic style.
  * <pre>
- * SpannableString string = new SpannableString("Text with typeface span");
- * string.setSpan(new TypefaceSpan("monospace"), 10, 18, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * Typeface myTypeface = Typeface.create(ResourcesCompat.getFont(context, R.font.acme),
+ * Typeface.BOLD);
+ * SpannableString string = new SpannableString("Text with typeface span.");
+ * string.setSpan(new TypefaceSpan(myTypeface), 10, 18, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ * string.setSpan(new TypefaceSpan("monospace"), 19, 22, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
  * </pre>
  * <img src="{@docRoot}reference/android/images/text/style/typefacespan.png" />
- * <figcaption>Text with "monospace" typeface family.</figcaption>
+ * <figcaption>Text with <code>TypefaceSpan</code>s constructed based on a font from resource and
+ * from a font family.</figcaption>
  */
 public class TypefaceSpan extends MetricAffectingSpan implements ParcelableSpan {
 
+    @Nullable
     private final String mFamily;
 
+    @Nullable
+    private final Typeface mTypeface;
+
     /**
-     * Constructs a {@link TypefaceSpan} based on a font family.
+     * Constructs a {@link TypefaceSpan} based on the font family. The previous style of the
+     * TextPaint is kept. If the font family is null, the text paint is not modified.
      *
-     * @param family The font family for this typeface. Examples include
-     *               "monospace", "serif", and "sans-serif".
+     * @param family The font family for this typeface.  Examples include
+     *               "monospace", "serif", and "sans-serif"
      */
-    public TypefaceSpan(String family) {
-        mFamily = family;
+    public TypefaceSpan(@Nullable String family) {
+        this(family, null);
     }
 
+    /**
+     * Constructs a {@link TypefaceSpan} from a {@link Typeface}. The previous style of the
+     * TextPaint is overridden and the style of the typeface is used.
+     *
+     * @param typeface the typeface
+     */
+    public TypefaceSpan(@NonNull Typeface typeface) {
+        this(null, typeface);
+    }
+
+    /**
+     * Constructs a {@link TypefaceSpan} from a  parcel.
+     */
     public TypefaceSpan(@NonNull Parcel src) {
         mFamily = src.readString();
+        mTypeface = LeakyTypefaceStorage.readTypefaceFromParcel(src);
+    }
+
+    private TypefaceSpan(@Nullable String family, @Nullable Typeface typeface) {
+        mFamily = family;
+        mTypeface = typeface;
     }
 
     @Override
@@ -79,37 +117,59 @@
     @Override
     public void writeToParcelInternal(@NonNull Parcel dest, int flags) {
         dest.writeString(mFamily);
+        LeakyTypefaceStorage.writeTypefaceToParcel(mTypeface, dest);
     }
 
     /**
-     * Returns the font family name.
+     * Returns the font family name set in the span.
+     *
+     * @return the font family name
+     * @see #TypefaceSpan(String)
      */
+    @Nullable
     public String getFamily() {
         return mFamily;
     }
 
-    @Override
-    public void updateDrawState(@NonNull TextPaint textPaint) {
-        apply(textPaint, mFamily);
+    /**
+     * Returns the typeface set in the span.
+     *
+     * @return the typeface set
+     * @see #TypefaceSpan(Typeface)
+     */
+    @Nullable
+    public Typeface getTypeface() {
+        return mTypeface;
     }
 
     @Override
-    public void updateMeasureState(@NonNull TextPaint textPaint) {
-        apply(textPaint, mFamily);
+    public void updateDrawState(@NonNull TextPaint ds) {
+        updateTypeface(ds);
     }
 
-    private static void apply(@NonNull Paint paint, String family) {
-        int oldStyle;
+    @Override
+    public void updateMeasureState(@NonNull TextPaint paint) {
+        updateTypeface(paint);
+    }
 
+    private void updateTypeface(@NonNull Paint paint) {
+        if (mTypeface != null) {
+            paint.setTypeface(mTypeface);
+        } else if (mFamily != null) {
+            applyFontFamily(paint, mFamily);
+        }
+    }
+
+    private void applyFontFamily(@NonNull Paint paint, @NonNull String family) {
+        int style;
         Typeface old = paint.getTypeface();
         if (old == null) {
-            oldStyle = 0;
+            style = Typeface.NORMAL;
         } else {
-            oldStyle = old.getStyle();
+            style = old.getStyle();
         }
-
-        Typeface tf = Typeface.create(family, oldStyle);
-        int fake = oldStyle & ~tf.getStyle();
+        final Typeface styledTypeface = Typeface.create(family, style);
+        int fake = style & ~styledTypeface.getStyle();
 
         if ((fake & Typeface.BOLD) != 0) {
             paint.setFakeBoldText(true);
@@ -118,7 +178,6 @@
         if ((fake & Typeface.ITALIC) != 0) {
             paint.setTextSkewX(-0.25f);
         }
-
-        paint.setTypeface(tf);
+        paint.setTypeface(styledTypeface);
     }
 }
diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java
index d973d4a..3a22db2 100644
--- a/core/java/android/text/util/Linkify.java
+++ b/core/java/android/text/util/Linkify.java
@@ -644,7 +644,13 @@
             @Nullable Runnable modifyTextView) {
         Preconditions.checkNotNull(text);
         Preconditions.checkNotNull(classifier);
-        final Supplier<TextLinks> supplier = () -> classifier.generateLinks(text, options);
+
+        // The input text may exceed the maximum length the text classifier can handle. In such
+        // cases, we process the text up to the maximum length.
+        final CharSequence truncatedText = text.subSequence(
+                0, Math.min(text.length(), classifier.getMaxGenerateLinksTextLength()));
+
+        final Supplier<TextLinks> supplier = () -> classifier.generateLinks(truncatedText, options);
         final Consumer<TextLinks> consumer = links -> {
             if (links.getLinks().isEmpty()) {
                 if (callback != null) {
@@ -653,7 +659,8 @@
                 return;
             }
 
-            final TextLinkSpan[] old = text.getSpans(0, text.length(), TextLinkSpan.class);
+            // Remove spans only for the part of the text we generated links for.
+            final TextLinkSpan[] old = text.getSpans(0, truncatedText.length(), TextLinkSpan.class);
             for (int i = old.length - 1; i >= 0; i--) {
                 text.removeSpan(old[i]);
             }
@@ -662,7 +669,8 @@
                     ? null : options.getSpanFactory();
             final @TextLinks.ApplyStrategy int applyStrategy = (options == null)
                     ? TextLinks.APPLY_STRATEGY_IGNORE : options.getApplyStrategy();
-            final @TextLinks.Status int result =  links.apply(text, applyStrategy, spanFactory);
+            final @TextLinks.Status int result = links.apply(text, applyStrategy, spanFactory,
+                    true /*allowPrefix*/);
             if (result == TextLinks.STATUS_LINKS_APPLIED) {
                 if (modifyTextView != null) {
                     modifyTextView.run();
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 3fd4696..8cb46b7 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -23,6 +23,10 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
 import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -396,6 +400,33 @@
         return true;
     }
 
+    /**
+     *  Get the Bitmap from the Drawable.
+     *
+     *  If the Bitmap needed to be scaled up to account for density, BitmapDrawable
+     *  handles this at draw time. But this class doesn't actually draw the Bitmap;
+     *  it is just a holder for native code to access its SkBitmap. So this needs to
+     *  get a version that is scaled to account for density.
+     */
+    private Bitmap getBitmapFromDrawable(BitmapDrawable bitmapDrawable) {
+        Bitmap bitmap = bitmapDrawable.getBitmap();
+        final int scaledWidth  = bitmapDrawable.getIntrinsicWidth();
+        final int scaledHeight = bitmapDrawable.getIntrinsicHeight();
+        if (scaledWidth == bitmap.getWidth() && scaledHeight == bitmap.getHeight()) {
+            return bitmap;
+        }
+
+        Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
+        RectF dst = new RectF(0, 0, scaledWidth, scaledHeight);
+
+        Bitmap scaled = Bitmap.createBitmap(scaledWidth, scaledHeight, bitmap.getConfig());
+        Canvas canvas = new Canvas(scaled);
+        Paint paint = new Paint();
+        paint.setFilterBitmap(true);
+        canvas.drawBitmap(bitmap, src, dst, paint);
+        return scaled;
+    }
+
     private void loadResource(Context context, Resources resources, @XmlRes int resourceId) {
         final XmlResourceParser parser = resources.getXml(resourceId);
         final int bitmapRes;
@@ -452,7 +483,8 @@
                                 + "is different. All frames should have the exact same size and "
                                 + "share the same hotspot.");
                     }
-                    mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap();
+                    BitmapDrawable bitmapDrawableFrame = (BitmapDrawable) drawableFrame;
+                    mBitmapFrames[i - 1] = getBitmapFromDrawable(bitmapDrawableFrame);
                 }
             }
         }
@@ -461,7 +493,8 @@
                     + "refer to a bitmap drawable.");
         }
 
-        final Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
+        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+        final Bitmap bitmap = getBitmapFromDrawable(bitmapDrawable);
         validateHotSpot(bitmap, hotSpotX, hotSpotY);
         // Set the properties now that we have successfully loaded the icon.
         mBitmap = bitmap;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index fc78211..bd7f8e5 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -152,7 +152,6 @@
     private static native void nativeSeverChildren(long transactionObj, long nativeObject);
     private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject,
             int scalingMode);
-    private static native void nativeDestroy(long transactionObj, long nativeObject);
     private static native IBinder nativeGetHandle(long nativeObject);
     private static native boolean nativeGetTransformToDisplayInverse(long nativeObject);
 
@@ -1571,16 +1570,6 @@
             return this;
         }
 
-        /**
-         * Same as {@link #destroy()} except this is invoked in a transaction instead of
-         * immediately.
-         */
-        public Transaction destroy(SurfaceControl sc) {
-            sc.checkNotReleased();
-            nativeDestroy(mNativeObject, sc.mNativeObject);
-            return this;
-        }
-
         public Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
             if (displayToken == null) {
                 throw new IllegalArgumentException("displayToken must not be null");
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2d85a58..3ff3c97 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -8010,6 +8010,9 @@
      *   <li>Call {@link
      *    android.view.autofill.AutofillManager#notifyViewVisibilityChanged(View, int, boolean)}
      *       when the visibility of a virtual child changed.
+     *   <li>Call
+     *    {@link android.view.autofill.AutofillManager#notifyViewClicked(View, int)} when a virtual
+     *       child is clicked.
      *   <li>Call {@link AutofillManager#commit()} when the autofill context of the view structure
      *       changed and the current context should be committed (for example, when the user tapped
      *       a {@code SUBMIT} button in an HTML page).
@@ -8807,6 +8810,9 @@
     /**
      * Computes whether this virtual autofill view is visible to the user.
      *
+     * <p><b>Note: </b>By default it returns {@code true}, but views providing a virtual hierarchy
+     * view must override it.
+     *
      * @return Whether the view is visible on the screen.
      */
     public boolean isVisibleToUserForAutofill(int virtualId) {
@@ -8819,7 +8825,7 @@
                 }
             }
         }
-        return false;
+        return true;
     }
 
     /**
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index 5ce2421..cb1d89c 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -38,6 +38,7 @@
     }
 
     /** @hide */
+    @TestApi
     public AutofillId(AutofillId parent, int virtualChildId) {
         mVirtual = true;
         mViewId = parent.mViewId;
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index b0e8a3e..7792fa6 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -72,10 +72,9 @@
 import java.util.List;
 import java.util.Objects;
 
+//TODO: use java.lang.ref.Cleaner once Android supports Java 9
 import sun.misc.Cleaner;
 
-// TODO: use java.lang.ref.Cleaner once Android supports Java 9
-
 /**
  * The {@link AutofillManager} provides ways for apps and custom views to integrate with the
  * Autofill Framework lifecycle.
@@ -1067,16 +1066,34 @@
     }
 
     /**
-     * Called when a {@link View} is clicked. Currently only used by views that should trigger save.
+     * Called to indicate a {@link View} is clicked.
      *
-     * @hide
+     * @param view view that has been clicked.
      */
-    public void notifyViewClicked(View view) {
-        final AutofillId id = view.getAutofillId();
+    public void notifyViewClicked(@NonNull View view) {
+        notifyViewClicked(view.getAutofillId());
+    }
 
+    /**
+     * Called to indicate a virtual view has been clicked.
+     *
+     * @param view the virtual view parent.
+     * @param virtualId id identifying the virtual child inside the parent view.
+     */
+    public void notifyViewClicked(@NonNull View view, int virtualId) {
+        notifyViewClicked(getAutofillId(view, virtualId));
+    }
+
+    private void notifyViewClicked(AutofillId id) {
+        if (!hasAutofillFeature()) {
+            return;
+        }
         if (sVerbose) Log.v(TAG, "notifyViewClicked(): id=" + id + ", trigger=" + mSaveTriggerId);
 
         synchronized (mLock) {
+            if (!mEnabled || !isActiveLocked()) {
+                return;
+            }
             if (mSaveTriggerId != null && mSaveTriggerId.equals(id)) {
                 if (sDebug) Log.d(TAG, "triggering commit by click of " + id);
                 commitLocked();
@@ -1091,16 +1108,16 @@
      *
      * @hide
      */
-    public void onActivityFinished() {
+    public void onActivityFinishing() {
         if (!hasAutofillFeature()) {
             return;
         }
         synchronized (mLock) {
             if (mSaveOnFinish) {
-                if (sDebug) Log.d(TAG, "Committing session on finish() as requested by service");
+                if (sDebug) Log.d(TAG, "onActivityFinishing(): calling commitLocked()");
                 commitLocked();
             } else {
-                if (sDebug) Log.d(TAG, "Cancelling session on finish() as requested by service");
+                if (sDebug) Log.d(TAG, "onActivityFinishing(): calling cancelLocked()");
                 cancelLocked();
             }
         }
@@ -1121,6 +1138,7 @@
         if (!hasAutofillFeature()) {
             return;
         }
+        if (sVerbose) Log.v(TAG, "commit() called by app");
         synchronized (mLock) {
             commitLocked();
         }
@@ -2334,6 +2352,7 @@
                 final boolean[] isVisible;
 
                 if (client.autofillClientIsVisibleForAutofill()) {
+                    if (sVerbose) Log.v(TAG, "client is visible, check tracked ids");
                     isVisible = client.autofillClientGetViewVisibility(trackedIds);
                 } else {
                     // All false
@@ -2353,7 +2372,7 @@
             }
 
             if (sVerbose) {
-                Log.v(TAG, "TrackedViews(trackedIds=" + trackedIds + "): "
+                Log.v(TAG, "TrackedViews(trackedIds=" + Arrays.toString(trackedIds) + "): "
                         + " mVisibleTrackedIds=" + mVisibleTrackedIds
                         + " mInvisibleTrackedIds=" + mInvisibleTrackedIds);
             }
@@ -2459,6 +2478,9 @@
             }
 
             if (mVisibleTrackedIds == null) {
+                if (sVerbose) {
+                    Log.v(TAG, "onVisibleForAutofillChangedLocked(): no more visible ids");
+                }
                 finishSessionLocked();
             }
         }
diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java
index af55dcd..cbc3828 100644
--- a/core/java/android/view/textclassifier/SystemTextClassifier.java
+++ b/core/java/android/view/textclassifier/SystemTextClassifier.java
@@ -121,6 +121,15 @@
         return mFallback.generateLinks(text, options);
     }
 
+    /**
+     * @inheritDoc
+     */
+    @Override
+    public int getMaxGenerateLinksTextLength() {
+        // TODO: retrieve this from the bound service.
+        return mFallback.getMaxGenerateLinksTextLength();
+    }
+
     private static final class TextSelectionCallback extends ITextSelectionCallback.Stub {
 
         final ResponseReceiver<TextSelection> mReceiver = new ResponseReceiver<>();
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 9f75c4a..2a62f23 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -276,9 +276,11 @@
      * @param text the text to generate annotations for
      * @param options configuration for link generation
      *
-     * @throws IllegalArgumentException if text is null
+     * @throws IllegalArgumentException if text is null or the text is too long for the
+     *      TextClassifier implementation.
      *
      * @see #generateLinks(CharSequence)
+     * @see #getMaxGenerateLinksTextLength()
      */
     @WorkerThread
     default TextLinks generateLinks(
@@ -299,9 +301,11 @@
      *
      * @param text the text to generate annotations for
      *
-     * @throws IllegalArgumentException if text is null
+     * @throws IllegalArgumentException if text is null or the text is too long for the
+     *      TextClassifier implementation.
      *
      * @see #generateLinks(CharSequence, TextLinks.Options)
+     * @see #getMaxGenerateLinksTextLength()
      */
     @WorkerThread
     default TextLinks generateLinks(@NonNull CharSequence text) {
@@ -309,6 +313,16 @@
     }
 
     /**
+     * Returns the maximal length of text that can be processed by generateLinks.
+     *
+     * @see #generateLinks(CharSequence)
+     * @see #generateLinks(CharSequence, TextLinks.Options)
+     */
+    default int getMaxGenerateLinksTextLength() {
+        return Integer.MAX_VALUE;
+    }
+
+    /**
      * Returns a {@link Collection} of the entity types in the specified preset.
      *
      * @see #ENTITY_PRESET_ALL
@@ -461,6 +475,15 @@
             checkMainThread(allowInMainThread);
         }
 
+        /**
+         * @throws IllegalArgumentException if text is null; the text is too long or options is null
+         */
+        public static void validate(@NonNull CharSequence text, int maxLength,
+                boolean allowInMainThread) {
+            validate(text, allowInMainThread);
+            Preconditions.checkArgumentInRange(text.length(), 0, maxLength, "text.length()");
+        }
+
         private static void checkMainThread(boolean allowInMainThread) {
             if (!allowInMainThread && Looper.myLooper() == Looper.getMainLooper()) {
                 Slog.w(DEFAULT_LOG_TAG, "TextClassifier called on main thread");
diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassifierConstants.java
index 00695b7..efa6948 100644
--- a/core/java/android/view/textclassifier/TextClassifierConstants.java
+++ b/core/java/android/view/textclassifier/TextClassifierConstants.java
@@ -47,10 +47,19 @@
             "smart_selection_enabled_for_edit_text";
     private static final String SMART_LINKIFY_ENABLED =
             "smart_linkify_enabled";
+    private static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
+            "suggest_selection_max_range_length";
+    private static final String CLASSIFY_TEXT_MAX_RANGE_LENGTH =
+            "classify_text_max_range_length";
+    private static final String GENERATE_LINKS_MAX_TEXT_LENGTH =
+            "generate_links_max_text_length";
 
     private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
     private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
     private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
+    private static final int SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
+    private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
+    private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
 
     /** Default settings. */
     static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
@@ -58,11 +67,17 @@
     private final boolean mDarkLaunch;
     private final boolean mSuggestSelectionEnabledForEditableText;
     private final boolean mSmartLinkifyEnabled;
+    private final int mSuggestSelectionMaxRangeLength;
+    private final int mClassifyTextMaxRangeLength;
+    private final int mGenerateLinksMaxTextLength;
 
     private TextClassifierConstants() {
         mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
         mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
         mSmartLinkifyEnabled = SMART_LINKIFY_ENABLED_DEFAULT;
+        mSuggestSelectionMaxRangeLength = SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT;
+        mClassifyTextMaxRangeLength = CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT;
+        mGenerateLinksMaxTextLength = GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT;
     }
 
     private TextClassifierConstants(@Nullable String settings) {
@@ -82,6 +97,15 @@
         mSmartLinkifyEnabled = parser.getBoolean(
                 SMART_LINKIFY_ENABLED,
                 SMART_LINKIFY_ENABLED_DEFAULT);
+        mSuggestSelectionMaxRangeLength = parser.getInt(
+                SUGGEST_SELECTION_MAX_RANGE_LENGTH,
+                SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
+        mClassifyTextMaxRangeLength = parser.getInt(
+                CLASSIFY_TEXT_MAX_RANGE_LENGTH,
+                CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT);
+        mGenerateLinksMaxTextLength = parser.getInt(
+                GENERATE_LINKS_MAX_TEXT_LENGTH,
+                GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT);
     }
 
     static TextClassifierConstants loadFromString(String settings) {
@@ -99,4 +123,16 @@
     public boolean isSmartLinkifyEnabled() {
         return mSmartLinkifyEnabled;
     }
+
+    public int getSuggestSelectionMaxRangeLength() {
+        return mSuggestSelectionMaxRangeLength;
+    }
+
+    public int getClassifyTextMaxRangeLength() {
+        return mClassifyTextMaxRangeLength;
+    }
+
+    public int getGenerateLinksMaxTextLength() {
+        return mGenerateLinksMaxTextLength;
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index fc03493..795caff 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -128,7 +128,9 @@
             @Nullable TextSelection.Options options) {
         Utils.validate(text, selectionStartIndex, selectionEndIndex, false /* allowInMainThread */);
         try {
-            if (text.length() > 0) {
+            final int rangeLength = selectionEndIndex - selectionStartIndex;
+            if (text.length() > 0
+                    && rangeLength <= getSettings().getSuggestSelectionMaxRangeLength()) {
                 final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                 final boolean darkLaunchAllowed = options != null && options.isDarkLaunchAllowed();
                 final SmartSelection smartSelection = getSmartSelection(locales);
@@ -183,7 +185,8 @@
             @Nullable TextClassification.Options options) {
         Utils.validate(text, startIndex, endIndex, false /* allowInMainThread */);
         try {
-            if (text.length() > 0) {
+            final int rangeLength = endIndex - startIndex;
+            if (text.length() > 0 && rangeLength <= getSettings().getClassifyTextMaxRangeLength()) {
                 final String string = text.toString();
                 final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                 final Calendar refTime = (options == null) ? null : options.getReferenceTime();
@@ -207,7 +210,7 @@
     @Override
     public TextLinks generateLinks(
             @NonNull CharSequence text, @Nullable TextLinks.Options options) {
-        Utils.validate(text, false /* allowInMainThread */);
+        Utils.validate(text, getMaxGenerateLinksTextLength(), false /* allowInMainThread */);
         final String textString = text.toString();
         final TextLinks.Builder builder = new TextLinks.Builder(textString);
 
@@ -241,6 +244,12 @@
         return mFallback.generateLinks(text, options);
     }
 
+    /** @inheritDoc */
+    @Override
+    public int getMaxGenerateLinksTextLength() {
+        return getSettings().getGenerateLinksMaxTextLength();
+    }
+
     @Override
     public Collection<String> getEntitiesForPreset(@TextClassifier.EntityPreset int entityPreset) {
         switch (entityPreset) {
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index d866d13..3d252f2 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -108,6 +108,7 @@
      * @param text the text to apply the links to. Must match the original text
      * @param applyStrategy strategy for resolving link conflicts
      * @param spanFactory a factory to generate spans from TextLinks. Will use a default if null
+     * @param allowPrefix whether to allow applying links only to a prefix of the text.
      *
      * @return a status code indicating whether or not the links were successfully applied
      *
@@ -117,10 +118,12 @@
     public int apply(
             @NonNull Spannable text,
             @ApplyStrategy int applyStrategy,
-            @Nullable Function<TextLink, TextLinkSpan> spanFactory) {
+            @Nullable Function<TextLink, TextLinkSpan> spanFactory,
+            boolean allowPrefix) {
         Preconditions.checkNotNull(text);
         checkValidApplyStrategy(applyStrategy);
-        if (!mFullText.equals(text.toString())) {
+        final String textString = text.toString();
+        if (!mFullText.equals(textString) && !(allowPrefix && textString.startsWith(mFullText))) {
             return STATUS_DIFFERENT_TEXT;
         }
         if (mLinks.isEmpty()) {
diff --git a/core/java/android/webkit/TracingConfig.java b/core/java/android/webkit/TracingConfig.java
index 75e2bf7..68badec 100644
--- a/core/java/android/webkit/TracingConfig.java
+++ b/core/java/android/webkit/TracingConfig.java
@@ -21,61 +21,76 @@
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 
 /**
  * Holds tracing configuration information and predefined settings.
  */
 public class TracingConfig {
 
-    private final String mCustomCategoryPattern;
-    private final @PresetCategories int mPresetCategories;
+    private @PredefinedCategories int mPredefinedCategories;
+    private final List<String> mCustomIncludedCategories = new ArrayList<String>();
     private @TracingMode int mTracingMode;
 
     /** @hide */
-    @IntDef({CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER, CATEGORIES_INPUT_LATENCY,
-            CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING, CATEGORIES_FRAME_VIEWER})
+    @IntDef(flag = true, value = {CATEGORIES_NONE, CATEGORIES_WEB_DEVELOPER,
+            CATEGORIES_INPUT_LATENCY, CATEGORIES_RENDERING, CATEGORIES_JAVASCRIPT_AND_RENDERING,
+            CATEGORIES_FRAME_VIEWER})
     @Retention(RetentionPolicy.SOURCE)
-    public @interface PresetCategories {}
+    public @interface PredefinedCategories {}
 
     /**
-     * Indicates that there are no preset categories.
+     * Indicates that there are no predefined categories.
      */
-    public static final int CATEGORIES_NONE = -1;
+    public static final int CATEGORIES_NONE = 0;
 
     /**
-     * Predefined categories typically useful for web developers.
+     * Predefined set of categories, includes all categories enabled by default in chromium.
+     * Use with caution: this setting may produce large trace output.
+     */
+    public static final int CATEGORIES_ALL = 1 << 0;
+
+    /**
+     * Predefined set of categories typically useful for analyzing WebViews.
+     * Typically includes android_webview and Java.
+     */
+    public static final int CATEGORIES_ANDROID_WEBVIEW = 1 << 1;
+
+    /**
+     * Predefined set of categories typically useful for web developers.
      * Typically includes blink, compositor, renderer.scheduler and v8 categories.
      */
-    public static final int CATEGORIES_WEB_DEVELOPER = 0;
+    public static final int CATEGORIES_WEB_DEVELOPER = 1 << 2;
 
     /**
-     * Predefined categories for analyzing input latency issues.
+     * Predefined set of categories for analyzing input latency issues.
      * Typically includes input, renderer.scheduler categories.
      */
-    public static final int CATEGORIES_INPUT_LATENCY = 1;
+    public static final int CATEGORIES_INPUT_LATENCY = 1 << 3;
 
     /**
-     * Predefined categories for analyzing rendering issues.
+     * Predefined set of categories for analyzing rendering issues.
      * Typically includes blink, compositor and gpu categories.
      */
-    public static final int CATEGORIES_RENDERING = 2;
+    public static final int CATEGORIES_RENDERING = 1 << 4;
 
     /**
-     * Predefined categories for analyzing javascript and rendering issues.
-     * Typically includes blink, compositor, gpu, renderer.schduler and v8 categories.
+     * Predefined set of categories for analyzing javascript and rendering issues.
+     * Typically includes blink, compositor, gpu, renderer.scheduler and v8 categories.
      */
-    public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 3;
+    public static final int CATEGORIES_JAVASCRIPT_AND_RENDERING = 1 << 5;
 
     /**
-     * Predefined categories for studying difficult rendering performance problems.
+     * Predefined set of categories for studying difficult rendering performance problems.
      * Typically includes blink, compositor, gpu, renderer.scheduler, v8 and
      * some other compositor categories which are disabled by default.
      */
-    public static final int CATEGORIES_FRAME_VIEWER = 4;
+    public static final int CATEGORIES_FRAME_VIEWER = 1 << 6;
 
     /** @hide */
-    @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER,
-            RECORD_TO_CONSOLE})
+    @IntDef({RECORD_UNTIL_FULL, RECORD_CONTINUOUSLY, RECORD_UNTIL_FULL_LARGE_BUFFER})
     @Retention(RetentionPolicy.SOURCE)
     public @interface TracingMode {}
 
@@ -97,99 +112,38 @@
 
     /**
      * Record trace events using a larger internal tracing buffer until it is full.
-     * Uses more memory than the other modes and may not be suitable on devices
-     * with smaller RAM. Depending on the implementation typically allows up to
-     * 512 million events to be stored.
+     * Uses significantly more memory than {@link #RECORD_UNTIL_FULL} and may not be
+     * suitable on devices with smaller RAM.
      */
     public static final int RECORD_UNTIL_FULL_LARGE_BUFFER = 2;
 
     /**
-     * Record trace events to console (logcat). The events are discarded and nothing
-     * is sent back to the caller. Uses the least memory as compared to the other modes.
+     * @hide
      */
-    public static final int RECORD_TO_CONSOLE = 3;
-
-    /**
-     * Create config with the preset categories.
-     * <p>
-     * Example:
-     *    TracingConfig(CATEGORIES_WEB_DEVELOPER) -- records trace events from the "web developer"
-     *                                               preset categories.
-     *
-     * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
-     *                    {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
-     *                    {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
-     *                    {@link #CATEGORIES_FRAME_VIEWER}.
-     *
-     * Note: for specifying custom categories without presets use
-     * {@link #TracingConfig(int, String, int)}.
-     *
-     */
-    public TracingConfig(@PresetCategories int presetCategories) {
-        this(presetCategories, "", RECORD_UNTIL_FULL);
+    public TracingConfig(@PredefinedCategories int predefinedCategories,
+            @NonNull List<String> customIncludedCategories,
+            @TracingMode int tracingMode) {
+        mPredefinedCategories = predefinedCategories;
+        mCustomIncludedCategories.addAll(customIncludedCategories);
+        mTracingMode = tracingMode;
     }
 
     /**
-     * Create a configuration with both preset categories and custom categories.
-     * Also allows to specify the tracing mode.
-     *
-     * Note that the categories are defined by the currently-in-use version of WebView. They live
-     * in chromium code and are not part of the Android API. See
-     * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
-     * chromium documentation on tracing</a> for more details.
-     *
-     * <p>
-     * Examples:
-     *
-     *  Preset category with a specified trace mode:
-     *    TracingConfig(CATEGORIES_WEB_DEVELOPER, "", RECORD_UNTIL_FULL_LARGE_BUFFER);
-     *  Custom categories:
-     *    TracingConfig(CATEGORIES_NONE, "browser", RECORD_UNTIL_FULL)
-     *      -- records only the trace events from the "browser" category.
-     *    TraceConfig(CATEGORIES_NONE, "-input,-gpu", RECORD_UNTIL_FULL)
-     *      -- records all trace events excluding the events from the "input" and 'gpu' categories.
-     *    TracingConfig(CATEGORIES_NONE, "blink*,devtools*", RECORD_UNTIL_FULL)
-     *      -- records only the trace events matching the "blink*" and "devtools*" patterns
-     *         (e.g. "blink_gc" and "devtools.timeline" categories).
-     *
-     *  Combination of preset and additional custom categories:
-     *    TracingConfig(CATEGORIES_WEB_DEVELOPER, "memory-infra", RECORD_CONTINUOUSLY)
-     *      -- records events from the "web developer" categories and events from the "memory-infra"
-     *         category to understand where memory is being used.
-     *
-     * @param presetCategories preset categories to use, one of {@link #CATEGORIES_WEB_DEVELOPER},
-     *                    {@link #CATEGORIES_INPUT_LATENCY}, {@link #CATEGORIES_RENDERING},
-     *                    {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
-     *                    {@link #CATEGORIES_FRAME_VIEWER}.
-     * @param customCategories a comma-delimited list of category wildcards. A category can
-     *                         have an optional '-' prefix to make it an excluded category.
-     * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
-     *                    {@link #RECORD_CONTINUOUSLY}, {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}
-     *                    or {@link #RECORD_TO_CONSOLE}.
+     * Returns a bitmask of the predefined categories values of this configuration.
      */
-    public TracingConfig(@PresetCategories int presetCategories,
-            @NonNull String customCategories, @TracingMode int tracingMode) {
-        mPresetCategories = presetCategories;
-        mCustomCategoryPattern = customCategories;
-        mTracingMode = RECORD_UNTIL_FULL;
+    @PredefinedCategories
+    public int getPredefinedCategories() {
+        return mPredefinedCategories;
     }
 
     /**
-     * Returns the custom category pattern for this configuration.
+     * Returns the list of included custom category patterns for this configuration.
      *
-     * @return empty string if no custom category pattern is specified.
+     * @return empty list if no custom category patterns are specified.
      */
     @NonNull
-    public String getCustomCategoryPattern() {
-        return mCustomCategoryPattern;
-    }
-
-    /**
-     * Returns the preset categories value of this configuration.
-     */
-    @PresetCategories
-    public int getPresetCategories() {
-        return mPresetCategories;
+    public List<String> getCustomIncludedCategories() {
+        return mCustomIncludedCategories;
     }
 
     /**
@@ -200,4 +154,111 @@
         return mTracingMode;
     }
 
+    /**
+     * Builder used to create {@link TracingConfig} objects.
+     *
+     * Examples:
+     *   new TracingConfig.Builder().build()
+     *       -- creates a configuration with default options: {@link #CATEGORIES_NONE},
+     *          {@link #RECORD_UNTIL_FULL}.
+     *   new TracingConfig.Builder().addCategories(CATEGORIES_WEB_DEVELOPER).build()
+     *       -- records trace events from the "web developer" predefined category sets.
+     *   new TracingConfig.Builder().addCategories(CATEGORIES_RENDERING,
+     *                                             CATEGORIES_INPUT_LATENCY).build()
+     *       -- records trace events from the "rendering" and "input latency" predefined
+     *          category sets.
+     *   new TracingConfig.Builder().addCategories("browser").build()
+     *       -- records only the trace events from the "browser" category.
+     *   new TracingConfig.Builder().addCategories("blink*","renderer*").build()
+     *       -- records only the trace events matching the "blink*" and "renderer*" patterns
+     *          (e.g. "blink.animations", "renderer_host" and "renderer.scheduler" categories).
+     *   new TracingConfig.Builder().addCategories(CATEGORIES_WEB_DEVELOPER)
+     *                              .addCategories("disabled-by-default-v8.gc")
+     *                              .setTracingMode(RECORD_CONTINUOUSLY).build()
+     *       -- records events from the "web developer" predefined category set and events from
+     *          the "disabled-by-default-v8.gc" category to understand where garbage collection
+     *          is being triggered. Uses a ring buffer for internal storage during tracing.
+     */
+    public static class Builder {
+        private @PredefinedCategories int mPredefinedCategories = CATEGORIES_NONE;
+        private final List<String> mCustomIncludedCategories = new ArrayList<String>();
+        private @TracingMode int mTracingMode = RECORD_UNTIL_FULL;
+
+        /**
+         * Default constructor for Builder.
+         */
+        public Builder() {}
+
+        /**
+         * Build {@link TracingConfig} using the current settings.
+         */
+        public TracingConfig build() {
+            return new TracingConfig(mPredefinedCategories, mCustomIncludedCategories,
+                    mTracingMode);
+        }
+
+        /**
+         * Adds categories from a predefined set of categories to be included in the trace output.
+         *
+         * @param predefinedCategories list or bitmask of predefined category sets to use:
+         *                    {@link #CATEGORIES_NONE}, {@link #CATEGORIES_ALL},
+         *                    {@link #CATEGORIES_WEB_DEVELOPER}, {@link #CATEGORIES_INPUT_LATENCY},
+         *                    {@link #CATEGORIES_RENDERING},
+         *                    {@link #CATEGORIES_JAVASCRIPT_AND_RENDERING} or
+         *                    {@link #CATEGORIES_FRAME_VIEWER}.
+         * @return The builder to facilitate chaining.
+         */
+        public Builder addCategories(@PredefinedCategories int... predefinedCategories) {
+            for (int categorySet : predefinedCategories) {
+                mPredefinedCategories |= categorySet;
+            }
+            return this;
+        }
+
+        /**
+         * Adds custom categories to be included in trace output.
+         *
+         * Note that the categories are defined by the currently-in-use version of WebView. They
+         * live in chromium code and are not part of the Android API. See
+         * See <a href="https://www.chromium.org/developers/how-tos/trace-event-profiling-tool">
+         * chromium documentation on tracing</a> for more details.
+         *
+         * @param categories a list of category patterns. A category pattern can contain wilcards,
+         *        e.g. "blink*" or full category name e.g. "renderer.scheduler".
+         * @return The builder to facilitate chaining.
+         */
+        public Builder addCategories(String... categories) {
+            for (String category: categories) {
+                mCustomIncludedCategories.add(category);
+            }
+            return this;
+        }
+
+        /**
+         * Adds custom categories to be included in trace output.
+         *
+         * Same as {@link #addCategories(String...)} but allows to pass a Collection as a parameter.
+         *
+         * @param categories a list of category patters.
+         * @return The builder to facilitate chaining.
+         */
+        public Builder addCategories(Collection<String> categories) {
+            mCustomIncludedCategories.addAll(categories);
+            return this;
+        }
+
+        /**
+         * Sets the tracing mode for this configuration.
+         *
+         * @param tracingMode tracing mode to use, one of {@link #RECORD_UNTIL_FULL},
+         *                    {@link #RECORD_CONTINUOUSLY} or
+         *                    {@link #RECORD_UNTIL_FULL_LARGE_BUFFER}.
+         * @return The builder to facilitate chaining.
+         */
+        public Builder setTracingMode(@TracingMode int tracingMode) {
+            mTracingMode = tracingMode;
+            return this;
+        }
+    }
+
 }
diff --git a/core/java/android/webkit/TracingController.java b/core/java/android/webkit/TracingController.java
index cadb8a1..7871021 100644
--- a/core/java/android/webkit/TracingController.java
+++ b/core/java/android/webkit/TracingController.java
@@ -16,9 +16,12 @@
 
 package android.webkit;
 
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.Handler;
+
+import java.io.OutputStream;
+import java.util.concurrent.Executor;
 
 /**
  * Manages tracing of WebViews. In particular provides functionality for the app
@@ -29,40 +32,22 @@
  * The resulting trace data is sent back as a byte sequence in json format. This
  * file can be loaded in "chrome://tracing" for further analysis.
  * <p>
- * Note: All methods in this class must be called on the UI thread. All callbacks
- * are also called on the UI thread.
- * <p>
  * Example usage:
  * <pre class="prettyprint">
  * TracingController tracingController = TracingController.getInstance();
- * tracingController.start(new TraceConfig(CATEGORIES_WEB_DEVELOPER));
+ * tracingController.start(new TraceConfig.Builder()
+ *                  .addCategories(CATEGORIES_WEB_DEVELOPER).build());
  * [..]
- * tracingController.stopAndFlush(new TraceFileOutput("trace.json"), null);
+ * tracingController.stop(new FileOutputStream("trace.json"),
+ *                        Executors.newSingleThreadExecutor());
  * </pre></p>
  */
 public abstract class TracingController {
 
     /**
-     * Interface for capturing tracing data.
-     */
-    public interface TracingOutputStream {
-        /**
-         * Will be called to return tracing data in chunks.
-         * Tracing data is returned in json format an array of bytes.
-         */
-        void write(byte[] chunk);
-
-        /**
-         * Called when tracing is finished and the data collection is over.
-         * There will be no calls to #write after #complete is called.
-         */
-        void complete();
-    }
-
-    /**
      * Returns the default TracingController instance. At present there is
      * only one TracingController instance for all WebView instances,
-     * however this restriction may be relaxed in the future.
+     * however this restriction may be relaxed in a future Android release.
      *
      * @return the default TracingController instance
      */
@@ -72,55 +57,38 @@
     }
 
     /**
-     * Starts tracing all webviews. Depeding on the trace mode in traceConfig
+     * Starts tracing all webviews. Depending on the trace mode in traceConfig
      * specifies how the trace events are recorded.
      *
      * For tracing modes {@link TracingConfig#RECORD_UNTIL_FULL},
      * {@link TracingConfig#RECORD_CONTINUOUSLY} and
      * {@link TracingConfig#RECORD_UNTIL_FULL_LARGE_BUFFER} the events are recorded
      * using an internal buffer and flushed to the outputStream when
-     * {@link #stopAndFlush(TracingOutputStream, Handler)} is called.
+     * {@link #stop(OutputStream, Executor)} is called.
      *
      * @param tracingConfig configuration options to use for tracing
-     * @return false if the system is already tracing, true otherwise.
+     * @throws IllegalStateException if the system is already tracing.
      */
-    public abstract boolean start(TracingConfig tracingConfig);
+    public abstract void start(@NonNull TracingConfig tracingConfig);
 
     /**
-     * Stops tracing and discards all tracing data.
+     * Stops tracing and flushes tracing data to the specified outputStream.
      *
-     * This method is particularly useful in conjunction with the
-     * {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode because tracing data is logged to
-     * console and not sent to an outputStream as with
-     * {@link #stopAndFlush(TracingOutputStream, Handler)}.
+     * The data is sent to the specified output stream in json format typically
+     * in chunks by invoking {@link java.io.OutputStream#write(byte[])}. On completion
+     * the {@link java.io.OutputStream#close()} method is called.
      *
+     * @param outputStream the output steam the tracing data will be sent to. If null
+     *                     the tracing data will be discarded.
+     * @param executor the {@link java.util.concurrent.Executor} on which the
+     *        outputStream #write and #close methods will be invoked.
      * @return false if the system was not tracing at the time of the call, true
      *         otherwise.
      */
-    public abstract boolean stop();
-
-    /**
-     * Stops tracing and flushes tracing data to the specifid outputStream.
-     *
-     * Note that if the {@link TracingConfig#RECORD_TO_CONSOLE} tracing mode is used
-     * nothing will be sent to the outputStream and no TracingOuputStream methods will be
-     * called. In that case it is more convenient to just use {@link #stop()} instead.
-     *
-     * @param outputStream the output steam the tracing data will be sent to.
-     * @param handler the {@link android.os.Handler} on which the outputStream callbacks
-     *                will be invoked. If the handler is null the current thread's Looper
-     *                will be used.
-     * @return false if the system was not tracing at the time of the call, true
-     *         otherwise.
-     */
-    public abstract boolean stopAndFlush(TracingOutputStream outputStream,
-            @Nullable Handler handler);
+    public abstract boolean stop(@Nullable OutputStream outputStream,
+            @NonNull @CallbackExecutor Executor executor);
 
     /** True if the system is tracing */
     public abstract boolean isTracing();
 
-    // TODO: consider adding getTraceBufferUsage, percentage and approx event count.
-    // TODO: consider adding String getCategories(), for obtaining the actual list
-    // of categories used (given that presets are ints).
-
 }
diff --git a/core/java/android/webkit/TracingFileOutputStream.java b/core/java/android/webkit/TracingFileOutputStream.java
deleted file mode 100644
index 8a5fa36..0000000
--- a/core/java/android/webkit/TracingFileOutputStream.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2017 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.webkit;
-
-import android.annotation.NonNull;
-
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-
-/**
- * Simple TracingOutputStream implementation which writes the trace data from
- * {@link TracingController} to a new file.
- *
- */
-public class TracingFileOutputStream implements TracingController.TracingOutputStream {
-
-    private FileOutputStream mFileOutput;
-
-    public TracingFileOutputStream(@NonNull String filename) throws FileNotFoundException {
-        mFileOutput = new FileOutputStream(filename);
-    }
-
-    /**
-     * Writes bytes chunk to the file.
-     */
-    public void write(byte[] chunk) {
-        try {
-            mFileOutput.write(chunk);
-        } catch (IOException e) {
-            onIOException(e);
-        }
-    }
-
-    /**
-     * Closes the file.
-     */
-    public void complete() {
-        try {
-            mFileOutput.close();
-        } catch (IOException e) {
-            onIOException(e);
-        }
-    }
-
-    private void onIOException(IOException e) {
-        throw new RuntimeException(e);
-    }
-}
diff --git a/core/java/android/widget/OWNERS b/core/java/android/widget/OWNERS
index 2789bae..e4b2930 100644
--- a/core/java/android/widget/OWNERS
+++ b/core/java/android/widget/OWNERS
@@ -1,9 +1,11 @@
 per-file TextView.java = siyamed@google.com
 per-file TextView.java = nona@google.com
 per-file TextView.java = clarabayarri@google.com
+
 per-file EditText.java = siyamed@google.com
 per-file EditText.java = nona@google.com
 per-file EditText.java = clarabayarri@google.com
+
 per-file Editor.java = siyamed@google.com
 per-file Editor.java = nona@google.com
 per-file Editor.java = clarabayarri@google.com
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 5c4d4d2..c987147 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -183,13 +183,17 @@
     }
 
     private void setCheckedId(@IdRes int id) {
+        boolean changed = id != mCheckedId;
         mCheckedId = id;
+
         if (mOnCheckedChangeListener != null) {
             mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);
         }
-        final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
-        if (afm != null) {
-            afm.notifyValueChanged(this);
+        if (changed) {
+            final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
+            if (afm != null) {
+                afm.notifyValueChanged(this);
+            }
         }
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5710db3..1e02c30 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -791,11 +791,18 @@
     // mAutoSizeStepGranularityInPx.
     private boolean mHasPresetAutoSizeValues = false;
 
+    // Autofill-related attributes
+    //
     // Indicates whether the text was set statically or dynamically, so it can be used to
     // sanitize autofill requests.
     private boolean mTextSetFromXmlOrResourceId = false;
-    // Resource id used to set the text - used for autofill purposes.
+    // Resource id used to set the text.
     private @StringRes int mTextId = ResourceId.ID_NULL;
+    // Last value used on AFM.notifyValueChanged(), used to optimize autofill workflow by avoiding
+    // calls when the value did not change
+    private CharSequence mLastValueSentToAutofillManager;
+    //
+    // End of autofill-related attributes
 
     /**
      * Kick-start the font cache for the zygote process (to pay the cost of
@@ -5665,7 +5672,6 @@
         if (needEditableForNotification) {
             sendAfterTextChanged((Editable) text);
         } else {
-            // Always notify AutoFillManager - it will return right away if autofill is disabled.
             notifyAutoFillManagerAfterTextChangedIfNeeded();
         }
 
@@ -9697,11 +9703,21 @@
             return;
         }
         final AutofillManager afm = mContext.getSystemService(AutofillManager.class);
-        if (afm != null) {
+        if (afm == null) {
+            return;
+        }
+
+        if (mLastValueSentToAutofillManager == null
+                || !mLastValueSentToAutofillManager.equals(mText)) {
             if (android.view.autofill.Helper.sVerbose) {
-                Log.v(LOG_TAG, "sendAfterTextChanged(): notify AFM for text=" + mText);
+                Log.v(LOG_TAG, "notifying AFM after text changed");
             }
             afm.notifyValueChanged(TextView.this);
+            mLastValueSentToAutofillManager = mText;
+        } else {
+            if (android.view.autofill.Helper.sVerbose) {
+                Log.v(LOG_TAG, "not notifying AFM on unchanged text");
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
index 500c028..bf151c3 100644
--- a/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
+++ b/core/java/com/android/internal/colorextraction/drawable/GradientDrawable.java
@@ -57,6 +57,8 @@
     private int mMainColor;
     private int mSecondaryColor;
     private ValueAnimator mColorAnimation;
+    private int mMainColorTo;
+    private int mSecondaryColorTo;
 
     public GradientDrawable(@NonNull Context context) {
         mDensity = context.getResources().getDisplayMetrics().density;
@@ -76,7 +78,7 @@
     }
 
     public void setColors(int mainColor, int secondaryColor, boolean animated) {
-        if (mainColor == mMainColor && secondaryColor == mSecondaryColor) {
+        if (mainColor == mMainColorTo && secondaryColor == mSecondaryColorTo) {
             return;
         }
 
@@ -84,6 +86,9 @@
             mColorAnimation.cancel();
         }
 
+        mMainColorTo = mainColor;
+        mSecondaryColorTo = mainColor;
+
         if (animated) {
             final int mainFrom = mMainColor;
             final int secFrom = mSecondaryColor;
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index d6f8dc4..61d5031 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -604,6 +604,7 @@
     CameraInfo cameraInfo;
     status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);
     if (rc != NO_ERROR) {
+        ALOGE("%s: getCameraInfo error: %d", __FUNCTION__, rc);
         return rc;
     }
     int defaultOrientation = 0;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8ca5062..0ef5445 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -846,14 +846,6 @@
     transaction->setOverrideScalingMode(ctrl, scalingMode);
 }
 
-static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz,
-                                       jlong transactionObj,
-                                       jlong nativeObject) {
-    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
-    auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
-    transaction->destroySurface(ctrl);
-}
-
 static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) {
     auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
     return javaObjectForIBinder(env, ctrl->getHandle());
@@ -1005,8 +997,6 @@
             (void*)nativeSeverChildren } ,
     {"nativeSetOverrideScalingMode", "(JJI)V",
             (void*)nativeSetOverrideScalingMode },
-    {"nativeDestroy", "(JJ)V",
-            (void*)nativeDestroyInTransaction },
     {"nativeGetHandle", "(J)Landroid/os/IBinder;",
             (void*)nativeGetHandle },
     {"nativeScreenshotToBuffer",
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index e994d37..0911298 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -999,7 +999,7 @@
     <integer name="config_shortPressOnSleepBehavior">0</integer>
 
     <!-- Time to wait while a button is pressed before triggering a very long press. -->
-    <integer name="config_veryLongPressTimeout">6000</integer>
+    <integer name="config_veryLongPressTimeout">3500</integer>
 
     <!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
     <string name="widget_default_package_name" translatable="false"></string>
diff --git a/core/tests/coretests/src/android/text/OWNERS b/core/tests/coretests/src/android/text/OWNERS
index 9f2182e..a35c604 100644
--- a/core/tests/coretests/src/android/text/OWNERS
+++ b/core/tests/coretests/src/android/text/OWNERS
@@ -1,3 +1,5 @@
+set noparent
+
 siyamed@google.com
 nona@google.com
-clarabayarri@google.com
+clarabayarri@google.com
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index a8de374..430b30f 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -19,6 +19,7 @@
 import static org.hamcrest.CoreMatchers.not;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
 import android.os.LocaleList;
@@ -33,6 +34,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class TextClassificationManagerTest {
@@ -183,6 +186,7 @@
     @Test
     public void testGenerateLinks_none_config() {
         if (isTextClassifierDisabled()) return;
+
         String text = "The number is +12122537077. See you tonight!";
         assertThat(mClassifier.generateLinks(text, mLinksOptions.setEntityConfig(
                 new TextClassifier.EntityConfig(TextClassifier.ENTITY_PRESET_NONE))),
@@ -210,6 +214,25 @@
     }
 
     @Test
+    public void testGenerateLinks_maxLength() {
+        if (isTextClassifierDisabled()) return;
+        char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength()];
+        Arrays.fill(manySpaces, ' ');
+        TextLinks links = mClassifier.generateLinks(new String(manySpaces), null);
+        assertTrue(links.getLinks().isEmpty());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testGenerateLinks_tooLong() {
+        if (isTextClassifierDisabled()) {
+            throw new IllegalArgumentException("pass if disabled");
+        }
+        char[] manySpaces = new char[mClassifier.getMaxGenerateLinksTextLength() + 1];
+        Arrays.fill(manySpaces, ' ');
+        mClassifier.generateLinks(new String(manySpaces), null);
+    }
+
+    @Test
     public void testSetTextClassifier() {
         TextClassifier classifier = mock(TextClassifier.class);
         mTcm.setTextClassifier(classifier);
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index 7f4f9f7..79433ac 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -382,7 +382,7 @@
         TextClassifier textClassifier = textClassificationManager.getTextClassifier();
         Spannable content = new SpannableString("Call me at +19148277737");
         TextLinks links = textClassifier.generateLinks(content);
-        links.apply(content, TextLinks.APPLY_STRATEGY_REPLACE, null);
+        links.apply(content, TextLinks.APPLY_STRATEGY_REPLACE, null, false /* allowPrefix */);
 
         mActivityRule.runOnUiThread(() -> {
             textView.setText(content);
diff --git a/docs/html/reference/images/text/style/typefacespan.png b/docs/html/reference/images/text/style/typefacespan.png
index 67e2cf9..1651c39 100644
--- a/docs/html/reference/images/text/style/typefacespan.png
+++ b/docs/html/reference/images/text/style/typefacespan.png
Binary files differ
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index ee7abc5..3cca47b 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -25,7 +25,7 @@
 import android.annotation.RawRes;
 import android.content.ContentResolver;
 import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
+import android.content.res.AssetManager.AssetInputStream;
 import android.content.res.Resources;
 import android.graphics.drawable.AnimatedImageDrawable;
 import android.graphics.drawable.Drawable;
@@ -263,6 +263,63 @@
         }
     }
 
+    /**
+     * Takes ownership of the AssetInputStream.
+     *
+     * @hide
+     */
+    public static class AssetInputStreamSource extends Source {
+        public AssetInputStreamSource(@NonNull AssetInputStream ais,
+                @NonNull Resources res, @NonNull TypedValue value) {
+            mAssetInputStream = ais;
+            mResources = res;
+
+            if (value.density == TypedValue.DENSITY_DEFAULT) {
+                mDensity = DisplayMetrics.DENSITY_DEFAULT;
+            } else if (value.density != TypedValue.DENSITY_NONE) {
+                mDensity = value.density;
+            } else {
+                mDensity = Bitmap.DENSITY_NONE;
+            }
+        }
+
+        private AssetInputStream mAssetInputStream;
+        private final Resources  mResources;
+        private final int        mDensity;
+
+        @Override
+        public Resources getResources() { return mResources; }
+
+        @Override
+        public int getDensity() {
+            return mDensity;
+        }
+
+        @Override
+        public ImageDecoder createImageDecoder() throws IOException {
+            ImageDecoder decoder = null;
+            synchronized (this) {
+                if (mAssetInputStream == null) {
+                    throw new IOException("Cannot reuse AssetInputStreamSource");
+                }
+                AssetInputStream ais = mAssetInputStream;
+                mAssetInputStream = null;
+                try {
+                    long asset = ais.getNativeAsset();
+                    decoder = nCreate(asset);
+                } finally {
+                    if (decoder == null) {
+                        IoUtils.closeQuietly(ais);
+                    } else {
+                        decoder.mInputStream = ais;
+                        decoder.mOwnsInputStream = true;
+                    }
+                }
+                return decoder;
+            }
+        }
+    }
+
     private static class ResourceSource extends Source {
         ResourceSource(@NonNull Resources res, int resId) {
             mResources = res;
@@ -296,11 +353,7 @@
                     mResDensity = value.density;
                 }
 
-                if (!(is instanceof AssetManager.AssetInputStream)) {
-                    // This should never happen.
-                    throw new RuntimeException("Resource is not an asset?");
-                }
-                long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
+                long asset = ((AssetInputStream) is).getNativeAsset();
                 decoder = nCreate(asset);
             } finally {
                 if (decoder == null) {
@@ -444,6 +497,7 @@
     private boolean mPreferRamOverQuality = false;
     private boolean mAsAlphaMask = false;
     private Rect    mCropRect;
+    private Rect    mOutPaddingRect;
     private Source  mSource;
 
     private PostProcessor          mPostProcessor;
@@ -782,6 +836,18 @@
     }
 
     /**
+     *  Set a Rect for retrieving nine patch padding.
+     *
+     *  If the image is a nine patch, this Rect will be set to the padding
+     *  rectangle during decode. Otherwise it will not be modified.
+     *
+     *  @hide
+     */
+    public void setOutPaddingRect(@NonNull Rect outPadding) {
+        mOutPaddingRect = outPadding;
+    }
+
+    /**
      *  Specify whether the {@link Bitmap} should be mutable.
      *
      *  <p>By default, a {@link Bitmap} created will be immutable, but that can
@@ -892,7 +958,6 @@
                 postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
                 mMutable, mAllocator, mRequireUnpremultiplied,
                 mPreferRamOverQuality, mAsAlphaMask);
-
     }
 
     private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -965,7 +1030,10 @@
             if (np != null && NinePatch.isNinePatchChunk(np)) {
                 Rect opticalInsets = new Rect();
                 bm.getOpticalInsets(opticalInsets);
-                Rect padding = new Rect();
+                Rect padding = decoder.mOutPaddingRect;
+                if (padding == null) {
+                    padding = new Rect();
+                }
                 nGetPadding(decoder.mNativePtr, padding);
                 return new NinePatchDrawable(res, bm, np, padding,
                         opticalInsets, null);
@@ -1008,6 +1076,15 @@
             final int srcDensity = computeDensity(src, decoder);
             Bitmap bm = decoder.decodeBitmap();
             bm.setDensity(srcDensity);
+
+            Rect padding = decoder.mOutPaddingRect;
+            if (padding != null) {
+                byte[] np = bm.getNinePatchChunk();
+                if (np != null && NinePatch.isNinePatchChunk(np)) {
+                    nGetPadding(decoder.mNativePtr, padding);
+                }
+            }
+
             return bm;
         }
     }
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 7ad062a..44b783b 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -27,6 +27,7 @@
 import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Outline;
@@ -49,6 +50,7 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -111,7 +113,7 @@
      */
     @Deprecated
     public BitmapDrawable() {
-        mBitmapState = new BitmapState((Bitmap) null);
+        init(new BitmapState((Bitmap) null), null);
     }
 
     /**
@@ -124,8 +126,7 @@
     @SuppressWarnings("unused")
     @Deprecated
     public BitmapDrawable(Resources res) {
-        mBitmapState = new BitmapState((Bitmap) null);
-        mBitmapState.mTargetDensity = mTargetDensity;
+        init(new BitmapState((Bitmap) null), res);
     }
 
     /**
@@ -135,7 +136,7 @@
      */
     @Deprecated
     public BitmapDrawable(Bitmap bitmap) {
-        this(new BitmapState(bitmap), null);
+        init(new BitmapState(bitmap), null);
     }
 
     /**
@@ -143,8 +144,7 @@
      * the display metrics of the resources.
      */
     public BitmapDrawable(Resources res, Bitmap bitmap) {
-        this(new BitmapState(bitmap), res);
-        mBitmapState.mTargetDensity = mTargetDensity;
+        init(new BitmapState(bitmap), res);
     }
 
     /**
@@ -154,10 +154,7 @@
      */
     @Deprecated
     public BitmapDrawable(String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
-        }
+        this(null, filepath);
     }
 
     /**
@@ -165,10 +162,21 @@
      */
     @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
     public BitmapDrawable(Resources res, String filepath) {
-        this(new BitmapState(BitmapFactory.decodeFile(filepath)), null);
-        mBitmapState.mTargetDensity = mTargetDensity;
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+        Bitmap bitmap = null;
+        try (FileInputStream stream = new FileInputStream(filepath)) {
+            bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, stream),
+                    (decoder, info, src) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (Exception e) {
+            /*  do nothing. This matches the behavior of BitmapFactory.decodeFile()
+                If the exception happened on decode, mBitmapState.mBitmap will be null.
+            */
+        } finally {
+            init(new BitmapState(bitmap), res);
+            if (mBitmapState.mBitmap == null) {
+                android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath);
+            }
         }
     }
 
@@ -179,10 +187,7 @@
      */
     @Deprecated
     public BitmapDrawable(java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
-        }
+        this(null, is);
     }
 
     /**
@@ -190,10 +195,21 @@
      */
     @SuppressWarnings({ "unused", "ChainingConstructorIgnoresParameter" })
     public BitmapDrawable(Resources res, java.io.InputStream is) {
-        this(new BitmapState(BitmapFactory.decodeStream(is)), null);
-        mBitmapState.mTargetDensity = mTargetDensity;
-        if (mBitmapState.mBitmap == null) {
-            android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+        Bitmap bitmap = null;
+        try {
+            bitmap = ImageDecoder.decodeBitmap(ImageDecoder.createSource(res, is),
+                    (decoder, info, src) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (Exception e) {
+            /*  do nothing. This matches the behavior of BitmapFactory.decodeStream()
+                If the exception happened on decode, mBitmapState.mBitmap will be null.
+            */
+        } finally {
+            init(new BitmapState(bitmap), res);
+            if (mBitmapState.mBitmap == null) {
+                android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is);
+            }
         }
     }
 
@@ -812,9 +828,19 @@
                 }
             }
 
+            int density = Bitmap.DENSITY_NONE;
+            if (value.density == TypedValue.DENSITY_DEFAULT) {
+                density = DisplayMetrics.DENSITY_DEFAULT;
+            } else if (value.density != TypedValue.DENSITY_NONE) {
+                density = value.density;
+            }
+
             Bitmap bitmap = null;
             try (InputStream is = r.openRawResource(srcResId, value)) {
-                bitmap = BitmapFactory.decodeResourceStream(r, value, is, null, null);
+                ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+                bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                });
             } catch (Exception e) {
                 // Do nothing and pick up the error below.
             }
@@ -1013,14 +1039,21 @@
         }
     }
 
+    private BitmapDrawable(BitmapState state, Resources res) {
+        init(state, res);
+    }
+
     /**
-     * The one constructor to rule them all. This is called by all public
+     * The one helper to rule them all. This is called by all public & private
      * constructors to set the state and initialize local properties.
      */
-    private BitmapDrawable(BitmapState state, Resources res) {
+    private void init(BitmapState state, Resources res) {
         mBitmapState = state;
-
         updateLocalState(res);
+
+        if (mBitmapState != null && res != null) {
+            mBitmapState.mTargetDensity = mTargetDensity;
+        }
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 05533d7..8af2fd8 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -37,6 +37,7 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.NinePatch;
 import android.graphics.Outline;
@@ -50,11 +51,13 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.Log;
 import android.util.StateSet;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.View;
 
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
@@ -1179,6 +1182,10 @@
             return null;
         }
 
+        if (opts == null) {
+            return getBitmapDrawable(res, value, is);
+        }
+
         /*  ugh. The decodeStream contract is that we have already allocated
             the pad rect, but if the bitmap does not had a ninepatch chunk,
             then the pad will be ignored. If we could change this to lazily
@@ -1194,7 +1201,6 @@
         // an application in compatibility mode, without scaling those down
         // to the compatibility density only to have them scaled back up when
         // drawn to the screen.
-        if (opts == null) opts = new BitmapFactory.Options();
         opts.inScreenDensity = Drawable.resolveDensity(res, 0);
         Bitmap  bm = BitmapFactory.decodeResourceStream(res, value, is, pad, opts);
         if (bm != null) {
@@ -1211,6 +1217,33 @@
         return null;
     }
 
+    private static Drawable getBitmapDrawable(Resources res, TypedValue value, InputStream is) {
+        try {
+            ImageDecoder.Source source = null;
+            if (value != null) {
+                int density = Bitmap.DENSITY_NONE;
+                if (value.density == TypedValue.DENSITY_DEFAULT) {
+                    density = DisplayMetrics.DENSITY_DEFAULT;
+                } else if (value.density != TypedValue.DENSITY_NONE) {
+                    density = value.density;
+                }
+                source = ImageDecoder.createSource(res, is, density);
+            } else {
+                source = ImageDecoder.createSource(res, is);
+            }
+
+            return ImageDecoder.decodeDrawable(source, (decoder, info, src) -> {
+                decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+            });
+        } catch (IOException e) {
+            /*  do nothing.
+                If the exception happened on decode, the drawable will be null.
+            */
+            Log.e("Drawable", "Unable to decode stream: " + e);
+        }
+        return null;
+    }
+
     /**
      * Create a drawable from an XML document. For more information on how to
      * create resources in XML, see
@@ -1310,11 +1343,10 @@
         }
 
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, pathName);
-        try {
-            Bitmap bm = BitmapFactory.decodeFile(pathName);
-            if (bm != null) {
-                return drawableFromBitmap(null, bm, null, null, null, pathName);
-            }
+        try (FileInputStream stream = new FileInputStream(pathName)) {
+            return getBitmapDrawable(null, null, stream);
+        } catch(IOException e) {
+            // Do nothing; we will just return null if the FileInputStream had an error
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index 1790020..66f2a31 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -24,9 +24,9 @@
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
+import android.graphics.ImageDecoder;
 import android.graphics.Insets;
 import android.graphics.NinePatch;
 import android.graphics.Outline;
@@ -211,7 +211,8 @@
             restoreAlpha = -1;
         }
 
-        final boolean needsDensityScaling = canvas.getDensity() == 0;
+        final boolean needsDensityScaling = canvas.getDensity() == 0
+                && Bitmap.DENSITY_NONE != state.mNinePatch.getDensity();
         if (needsDensityScaling) {
             restoreToCount = restoreToCount >= 0 ? restoreToCount : canvas.save();
 
@@ -421,10 +422,6 @@
 
         final int srcResId = a.getResourceId(R.styleable.NinePatchDrawable_src, 0);
         if (srcResId != 0) {
-            final BitmapFactory.Options options = new BitmapFactory.Options();
-            options.inDither = !state.mDither;
-            options.inScreenDensity = r.getDisplayMetrics().noncompatDensityDpi;
-
             final Rect padding = new Rect();
             final Rect opticalInsets = new Rect();
             Bitmap bitmap = null;
@@ -433,7 +430,17 @@
                 final TypedValue value = new TypedValue();
                 final InputStream is = r.openRawResource(srcResId, value);
 
-                bitmap = BitmapFactory.decodeResourceStream(r, value, is, padding, options);
+                int density = Bitmap.DENSITY_NONE;
+                if (value.density == TypedValue.DENSITY_DEFAULT) {
+                    density = DisplayMetrics.DENSITY_DEFAULT;
+                } else if (value.density != TypedValue.DENSITY_NONE) {
+                    density = value.density;
+                }
+                ImageDecoder.Source source = ImageDecoder.createSource(r, is, density);
+                bitmap = ImageDecoder.decodeBitmap(source, (decoder, info, src) -> {
+                    decoder.setOutPaddingRect(padding);
+                    decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+                });
 
                 is.close();
             } catch (IOException e) {
@@ -660,8 +667,9 @@
             return;
         }
 
-        final int sourceDensity = ninePatch.getDensity();
         final int targetDensity = mTargetDensity;
+        final int sourceDensity = ninePatch.getDensity() == Bitmap.DENSITY_NONE ?
+            targetDensity : ninePatch.getDensity();
 
         final Insets sourceOpticalInsets = mNinePatchState.mOpticalInsets;
         if (sourceOpticalInsets != Insets.NONE) {
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index ded427e..e2aba04 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -545,7 +545,9 @@
         try {
             args = args != null ? args : new KeymasterArguments();
             entropy = entropy != null ? entropy : new byte[0];
-            return mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
+            OperationResult res = mBinder.begin(getToken(), alias, purpose, pruneable, args, entropy, uid);
+            // This result is -26 (KEY_USER_NOT_AUTHENTICATED) but why??
+            return res;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
@@ -563,7 +565,8 @@
         try {
             arguments = arguments != null ? arguments : new KeymasterArguments();
             input = input != null ? input : new byte[0];
-            return mBinder.update(token, arguments, input);
+            OperationResult res = mBinder.update(token, arguments, input);
+            return res;
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return null;
@@ -618,9 +621,9 @@
      * @return {@code KeyStore.NO_ERROR} on success, otherwise an error value corresponding to
      * a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
      */
-    public int addAuthToken(byte[] authToken) {
+    public int addAuthToken(byte[] authToken, int userId) {
         try {
-            return mBinder.addAuthToken(authToken);
+            return mBinder.addAuthToken(authToken, userId);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return SYSTEM_ERROR;
@@ -832,14 +835,14 @@
     public InvalidKeyException getInvalidKeyException(
             String keystoreKeyAlias, int uid, KeyStoreException e) {
         switch (e.getErrorCode()) {
-            case LOCKED:
+            case LOCKED: // 2
                 return new UserNotAuthenticatedException();
-            case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
+            case KeymasterDefs.KM_ERROR_KEY_EXPIRED: // -25
                 return new KeyExpiredException();
-            case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
+            case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID: // -2
                 return new KeyNotYetValidException();
-            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
-            case OP_AUTH_NEEDED:
+            case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED: // -26
+            case OP_AUTH_NEEDED: // 15
             {
                 // We now need to determine whether the key/operation can become usable if user
                 // authentication is performed, or whether it can never become usable again.
@@ -879,7 +882,7 @@
                 // None of the key's SIDs can ever be authenticated
                 return new KeyPermanentlyInvalidatedException();
             }
-            case UNINITIALIZED:
+            case UNINITIALIZED: // 3
                 return new KeyPermanentlyInvalidatedException();
             default:
                 return new InvalidKeyException("Keystore operation failed", e);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index 09b3b9b..419eb24 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -243,13 +243,7 @@
                 // Check that user authentication related parameters are acceptable. This method
                 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
                 // not set up).
-                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
-                        spec.isUserAuthenticationRequired(),
-                        spec.getUserAuthenticationValidityDurationSeconds(),
-                        spec.isUserAuthenticationValidWhileOnBody(),
-                        spec.isInvalidatedByBiometricEnrollment(),
-                        GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
-                        spec.isUserConfirmationRequired());
+                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
             } catch (IllegalStateException | IllegalArgumentException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
@@ -285,16 +279,7 @@
         args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
         args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
         args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
-        KeymasterUtils.addUserAuthArgs(args,
-                spec.isUserAuthenticationRequired(),
-                spec.getUserAuthenticationValidityDurationSeconds(),
-                spec.isUserAuthenticationValidWhileOnBody(),
-                spec.isInvalidatedByBiometricEnrollment(),
-                GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
-                spec.isUserConfirmationRequired());
-        if (spec.isTrustedUserPresenceRequired()) {
-            args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
-        }
+        KeymasterUtils.addUserAuthArgs(args, spec);
         KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
                 args,
                 mKeymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index e33e3cd..d68a33d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -344,13 +344,7 @@
                 // Check that user authentication related parameters are acceptable. This method
                 // will throw an IllegalStateException if there are issues (e.g., secure lock screen
                 // not set up).
-                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(),
-                        mSpec.isUserAuthenticationRequired(),
-                        mSpec.getUserAuthenticationValidityDurationSeconds(),
-                        mSpec.isUserAuthenticationValidWhileOnBody(),
-                        mSpec.isInvalidatedByBiometricEnrollment(),
-                        GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
-                        mSpec.isUserConfirmationRequired());
+                KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
             } catch (IllegalArgumentException | IllegalStateException e) {
                 throw new InvalidAlgorithmParameterException(e);
             }
@@ -541,13 +535,7 @@
         args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
         args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
 
-        KeymasterUtils.addUserAuthArgs(args,
-                mSpec.isUserAuthenticationRequired(),
-                mSpec.getUserAuthenticationValidityDurationSeconds(),
-                mSpec.isUserAuthenticationValidWhileOnBody(),
-                mSpec.isInvalidatedByBiometricEnrollment(),
-                GateKeeper.INVALID_SECURE_USER_ID /* boundToSpecificSecureUserId */,
-                mSpec.isUserConfirmationRequired());
+        KeymasterUtils.addUserAuthArgs(args, mSpec);
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
                 mSpec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 05cc74a..fc86ca0 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -497,13 +497,7 @@
                 importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
                 importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
                         KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
-                KeymasterUtils.addUserAuthArgs(importArgs,
-                        spec.isUserAuthenticationRequired(),
-                        spec.getUserAuthenticationValidityDurationSeconds(),
-                        spec.isUserAuthenticationValidWhileOnBody(),
-                        spec.isInvalidatedByBiometricEnrollment(),
-                        spec.getBoundToSpecificSecureUserId(),
-                        spec.isUserConfirmationRequired());
+                KeymasterUtils.addUserAuthArgs(importArgs, spec);
                 importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
                         spec.getKeyValidityStart());
                 importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
@@ -700,13 +694,7 @@
             int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
                     params.getEncryptionPaddings());
             args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
-            KeymasterUtils.addUserAuthArgs(args,
-                    params.isUserAuthenticationRequired(),
-                    params.getUserAuthenticationValidityDurationSeconds(),
-                    params.isUserAuthenticationValidWhileOnBody(),
-                    params.isInvalidatedByBiometricEnrollment(),
-                    params.getBoundToSpecificSecureUserId(),
-                    params.isUserConfirmationRequired());
+            KeymasterUtils.addUserAuthArgs(args, params);
             KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
                     args,
                     keymasterAlgorithm,
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index da23c70..d0814c6 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.app.KeyguardManager;
 import android.hardware.fingerprint.FingerprintManager;
+import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.text.TextUtils;
 
@@ -232,7 +233,7 @@
  * key = (SecretKey) keyStore.getKey("key2", null);
  * }</pre>
  */
-public final class KeyGenParameterSpec implements AlgorithmParameterSpec {
+public final class KeyGenParameterSpec implements AlgorithmParameterSpec, UserAuthArgs {
 
     private static final X500Principal DEFAULT_CERT_SUBJECT = new X500Principal("CN=fake");
     private static final BigInteger DEFAULT_CERT_SERIAL_NUMBER = new BigInteger("1");
@@ -265,6 +266,7 @@
     private final boolean mInvalidatedByBiometricEnrollment;
     private final boolean mIsStrongBoxBacked;
     private final boolean mUserConfirmationRequired;
+    private final boolean mUnlockedDeviceRequired;
 
     /**
      * @hide should be built with Builder
@@ -295,7 +297,8 @@
             boolean userAuthenticationValidWhileOnBody,
             boolean invalidatedByBiometricEnrollment,
             boolean isStrongBoxBacked,
-            boolean userConfirmationRequired) {
+            boolean userConfirmationRequired,
+            boolean unlockedDeviceRequired) {
         if (TextUtils.isEmpty(keyStoreAlias)) {
             throw new IllegalArgumentException("keyStoreAlias must not be empty");
         }
@@ -344,6 +347,7 @@
         mInvalidatedByBiometricEnrollment = invalidatedByBiometricEnrollment;
         mIsStrongBoxBacked = isStrongBoxBacked;
         mUserConfirmationRequired = userConfirmationRequired;
+        mUnlockedDeviceRequired = unlockedDeviceRequired;
     }
 
     /**
@@ -669,6 +673,22 @@
     }
 
     /**
+     * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+     *
+     * @see Builder#SetUnlockedDeviceRequired(boolean)
+     */
+    public boolean isUnlockedDeviceRequired() {
+        return mUnlockedDeviceRequired;
+    }
+
+    /**
+     * @hide
+     */
+    public long getBoundToSpecificSecureUserId() {
+        return GateKeeper.INVALID_SECURE_USER_ID;
+    }
+
+    /**
      * Builder of {@link KeyGenParameterSpec} instances.
      */
     public final static class Builder {
@@ -699,6 +719,7 @@
         private boolean mInvalidatedByBiometricEnrollment = true;
         private boolean mIsStrongBoxBacked = false;
         private boolean mUserConfirmationRequired;
+        private boolean mUnlockedDeviceRequired = false;
 
         /**
          * Creates a new instance of the {@code Builder}.
@@ -1267,6 +1288,18 @@
         }
 
         /**
+         * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+         * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+         * while the screen is locked will fail. A locked device requires a PIN, password,
+         * fingerprint, or other trusted factor to access.
+         */
+        @NonNull
+        public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+            mUnlockedDeviceRequired = unlockedDeviceRequired;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@code KeyGenParameterSpec}.
          */
         @NonNull
@@ -1297,7 +1330,8 @@
                     mUserAuthenticationValidWhileOnBody,
                     mInvalidatedByBiometricEnrollment,
                     mIsStrongBoxBacked,
-                    mUserConfirmationRequired);
+                    mUserConfirmationRequired,
+                    mUnlockedDeviceRequired);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index b5b3281..7f8259b 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -212,7 +212,7 @@
  * ...
  * }</pre>
  */
-public final class KeyProtection implements ProtectionParameter {
+public final class KeyProtection implements ProtectionParameter, UserAuthArgs {
     private final Date mKeyValidityStart;
     private final Date mKeyValidityForOriginationEnd;
     private final Date mKeyValidityForConsumptionEnd;
@@ -229,6 +229,8 @@
     private final long mBoundToSecureUserId;
     private final boolean mCriticalToDeviceEncryption;
     private final boolean mUserConfirmationRequired;
+    private final boolean mTrustedUserPresenceRequired;
+    private final boolean mUnlockedDeviceRequired;
 
     private KeyProtection(
             Date keyValidityStart,
@@ -242,11 +244,13 @@
             boolean randomizedEncryptionRequired,
             boolean userAuthenticationRequired,
             int userAuthenticationValidityDurationSeconds,
+            boolean trustedUserPresenceRequired,
             boolean userAuthenticationValidWhileOnBody,
             boolean invalidatedByBiometricEnrollment,
             long boundToSecureUserId,
             boolean criticalToDeviceEncryption,
-            boolean userConfirmationRequired) {
+            boolean userConfirmationRequired,
+            boolean unlockedDeviceRequired) {
         mKeyValidityStart = Utils.cloneIfNotNull(keyValidityStart);
         mKeyValidityForOriginationEnd = Utils.cloneIfNotNull(keyValidityForOriginationEnd);
         mKeyValidityForConsumptionEnd = Utils.cloneIfNotNull(keyValidityForConsumptionEnd);
@@ -265,6 +269,8 @@
         mBoundToSecureUserId = boundToSecureUserId;
         mCriticalToDeviceEncryption = criticalToDeviceEncryption;
         mUserConfirmationRequired = userConfirmationRequired;
+        mTrustedUserPresenceRequired = trustedUserPresenceRequired;
+        mUnlockedDeviceRequired = unlockedDeviceRequired;
     }
 
     /**
@@ -437,6 +443,14 @@
     }
 
     /**
+     * Returns {@code true} if the key is authorized to be used only if a test of user presence has
+     * been performed between the {@code Signature.initSign()} and {@code Signature.sign()} calls.
+     */
+    public boolean isTrustedUserPresenceRequired() {
+        return mTrustedUserPresenceRequired;
+    }
+
+    /**
      * Returns {@code true} if the key will be de-authorized when the device is removed from the
      * user's body.  This option has no effect on keys that don't have an authentication validity
      * duration, and has no effect if the device lacks an on-body sensor.
@@ -494,6 +508,15 @@
     }
 
     /**
+     * Returns {@code true} if the key cannot be used unless the device screen is unlocked.
+     *
+     * @see Builder#SetRequireDeviceUnlocked(boolean)
+     */
+    public boolean isUnlockedDeviceRequired() {
+        return mUnlockedDeviceRequired;
+    }
+
+    /**
      * Builder of {@link KeyProtection} instances.
      */
     public final static class Builder {
@@ -512,6 +535,9 @@
         private boolean mUserAuthenticationValidWhileOnBody;
         private boolean mInvalidatedByBiometricEnrollment = true;
         private boolean mUserConfirmationRequired;
+        private boolean mTrustedUserPresenceRequired = false;
+        private boolean mUnlockedDeviceRequired = false;
+
         private long mBoundToSecureUserId = GateKeeper.INVALID_SECURE_USER_ID;
         private boolean mCriticalToDeviceEncryption = false;
 
@@ -811,6 +837,16 @@
         }
 
         /**
+         * Sets whether a test of user presence is required to be performed between the
+         * {@code Signature.initSign()} and {@code Signature.sign()} method calls.
+         */
+        @NonNull
+        public Builder setTrustedUserPresenceRequired(boolean required) {
+            mTrustedUserPresenceRequired = required;
+            return this;
+        }
+
+        /**
          * Sets whether the key will remain authorized only until the device is removed from the
          * user's body up to the limit of the authentication validity period (see
          * {@link #setUserAuthenticationValidityDurationSeconds} and
@@ -892,6 +928,18 @@
         }
 
         /**
+         * Sets whether the keystore requires the screen to be unlocked before allowing decryption
+         * using this key. If this is set to {@code true}, any attempt to decrypt using this key
+         * while the screen is locked will fail. A locked device requires a PIN, password,
+         * fingerprint, or other trusted factor to access.
+         */
+        @NonNull
+        public Builder setUnlockedDeviceRequired(boolean unlockedDeviceRequired) {
+            mUnlockedDeviceRequired = unlockedDeviceRequired;
+            return this;
+        }
+
+        /**
          * Builds an instance of {@link KeyProtection}.
          *
          * @throws IllegalArgumentException if a required field is missing
@@ -910,11 +958,13 @@
                     mRandomizedEncryptionRequired,
                     mUserAuthenticationRequired,
                     mUserAuthenticationValidityDurationSeconds,
+                    mTrustedUserPresenceRequired,
                     mUserAuthenticationValidWhileOnBody,
                     mInvalidatedByBiometricEnrollment,
                     mBoundToSecureUserId,
                     mCriticalToDeviceEncryption,
-                    mUserConfirmationRequired);
+                    mUserConfirmationRequired,
+                    mUnlockedDeviceRequired);
         }
     }
 }
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 4e28601..5bd0e74 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -18,6 +18,7 @@
 
 import android.util.Log;
 import android.hardware.fingerprint.FingerprintManager;
+import android.os.UserHandle;
 import android.security.GateKeeper;
 import android.security.KeyStore;
 import android.security.keymaster.KeymasterArguments;
@@ -101,22 +102,27 @@
      *         require user authentication.
      */
     public static void addUserAuthArgs(KeymasterArguments args,
-            boolean userAuthenticationRequired,
-            int userAuthenticationValidityDurationSeconds,
-            boolean userAuthenticationValidWhileOnBody,
-            boolean invalidatedByBiometricEnrollment,
-            long boundToSpecificSecureUserId,
-            boolean userConfirmationRequired) {
-        if (userConfirmationRequired) {
+            UserAuthArgs spec) {
+        if (spec.isTrustedUserPresenceRequired()) {
+            args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
+        }
+
+        if (spec.isUserConfirmationRequired()) {
             args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
         }
 
-        if (!userAuthenticationRequired) {
+        if (spec.isUnlockedDeviceRequired()) {
+            args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
+            // Once keymaster is properly ignoring this tag, it should be added to every auth list
+            args.addUnsignedInt(KeymasterDefs.KM_TAG_USER_ID, UserHandle.getCallingUserId());
+        }
+
+        if (!spec.isUserAuthenticationRequired()) {
             args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
             return;
         }
 
-        if (userAuthenticationValidityDurationSeconds == -1) {
+        if (spec.getUserAuthenticationValidityDurationSeconds() == -1) {
             // Every use of this key needs to be authorized by the user. This currently means
             // fingerprint-only auth.
             FingerprintManager fingerprintManager =
@@ -132,9 +138,9 @@
             }
 
             long sid;
-            if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
-                sid = boundToSpecificSecureUserId;
-            } else if (invalidatedByBiometricEnrollment) {
+            if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+                sid = spec.getBoundToSpecificSecureUserId();
+            } else if (spec.isInvalidatedByBiometricEnrollment()) {
                 // The fingerprint-only SID will change on fingerprint enrollment or removal of all,
                 // enrolled fingerprints, invalidating the key.
                 sid = fingerprintOnlySid;
@@ -147,14 +153,14 @@
             args.addUnsignedLong(
                     KeymasterDefs.KM_TAG_USER_SECURE_ID, KeymasterArguments.toUint64(sid));
             args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, KeymasterDefs.HW_AUTH_FINGERPRINT);
-            if (userAuthenticationValidWhileOnBody) {
+            if (spec.isUserAuthenticationValidWhileOnBody()) {
                 throw new ProviderException("Key validity extension while device is on-body is not "
                         + "supported for keys requiring fingerprint authentication");
             }
         } else {
             long sid;
-            if (boundToSpecificSecureUserId != GateKeeper.INVALID_SECURE_USER_ID) {
-                sid = boundToSpecificSecureUserId;
+            if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
+                sid = spec.getBoundToSpecificSecureUserId();
             } else {
                 // The key is authorized for use for the specified amount of time after the user has
                 // authenticated. Whatever unlocks the secure lock screen should authorize this key.
@@ -165,8 +171,8 @@
             args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE,
                     KeymasterDefs.HW_AUTH_PASSWORD | KeymasterDefs.HW_AUTH_FINGERPRINT);
             args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
-                    userAuthenticationValidityDurationSeconds);
-            if (userAuthenticationValidWhileOnBody) {
+                    spec.getUserAuthenticationValidityDurationSeconds());
+            if (spec.isUserAuthenticationValidWhileOnBody()) {
                 args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
             }
         }
diff --git a/keystore/java/android/security/keystore/UserAuthArgs.java b/keystore/java/android/security/keystore/UserAuthArgs.java
new file mode 100644
index 0000000..3a7017e
--- /dev/null
+++ b/keystore/java/android/security/keystore/UserAuthArgs.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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.security.keystore;
+
+/**
+ * @hide
+ *
+ * This is an interface to encapsulate the user authentication arguments that
+ * are passed to KeymasterUtils.addUserAuthArgs. Classes that represent
+ * authorization characteristics for new or imported keys can implement this
+ * interface to be passed to that method.
+ */
+public interface UserAuthArgs {
+
+    boolean isUserAuthenticationRequired();
+    int getUserAuthenticationValidityDurationSeconds();
+    boolean isUserAuthenticationValidWhileOnBody();
+    boolean isInvalidatedByBiometricEnrollment();
+    boolean isTrustedUserPresenceRequired();
+    boolean isUnlockedDeviceRequired();
+    boolean isUserConfirmationRequired();
+    long getBoundToSpecificSecureUserId();
+
+}
diff --git a/media/java/android/media/DataSourceDesc.java b/media/java/android/media/DataSourceDesc.java
index 73fad7a..6dff07f 100644
--- a/media/java/android/media/DataSourceDesc.java
+++ b/media/java/android/media/DataSourceDesc.java
@@ -30,6 +30,8 @@
 import java.io.FileDescriptor;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.net.CookieHandler;
+import java.net.CookieManager;
 import java.net.HttpCookie;
 
 import java.util.ArrayList;
@@ -433,10 +435,22 @@
          * @param cookies the cookies to be sent together with the request
          * @return the same Builder instance.
          * @throws NullPointerException if context or uri is null.
+         * @throws IllegalArgumentException if the cookie handler is not of CookieManager type
+         *                                  when cookies are provided.
          */
         public Builder setDataSource(@NonNull Context context, @NonNull Uri uri,
                 @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies) {
+            Preconditions.checkNotNull(context, "context cannot be null");
             Preconditions.checkNotNull(uri);
+            if (cookies != null) {
+                CookieHandler cookieHandler = CookieHandler.getDefault();
+                if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
+                    throw new IllegalArgumentException(
+                            "The cookie handler has to be of CookieManager type "
+                            + "when cookies are provided.");
+                }
+            }
+
             resetDataSource();
             mType = TYPE_URI;
             mUri = uri;
diff --git a/media/java/android/media/MediaPlayer2.java b/media/java/android/media/MediaPlayer2.java
index e331b2c..2f3d972 100644
--- a/media/java/android/media/MediaPlayer2.java
+++ b/media/java/android/media/MediaPlayer2.java
@@ -804,19 +804,6 @@
     public abstract DataSourceDesc editPlaylistItem(int index, DataSourceDesc dsd);
 
     /**
-     * Prepares the player for playback, synchronously.
-     *
-     * After setting the datasource and the display surface, you need to either
-     * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
-     * which blocks until MediaPlayer2 is ready for playback.
-     *
-     * @throws IOException if source can not be accessed
-     * @throws IllegalStateException if it is called in an invalid state
-     * @hide
-     */
-    public void prepare() throws IOException { }
-
-    /**
      * Prepares the player for playback, asynchronously.
      *
      * After setting the datasource and the display surface, you need to
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index b805eb4..1b21b5b 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -137,7 +137,7 @@
  *         {@link #getVideoWidth()}, {@link #setAudioAttributes(AudioAttributes)},
  *         {@link #setLooping(boolean)},
  *         {@link #setVolume(float, float)}, {@link #pause()}, {@link #play()},
- *         {@link #seekTo(long, int)}, {@link #prepare()} or
+ *         {@link #seekTo(long, int)} or
  *         {@link #prepareAsync()} in the <em>Idle</em> state for both cases. If any of these
  *         methods is called right after a MediaPlayer2 object is constructed,
  *         the user supplied callback method OnErrorListener.onError() won't be
@@ -184,7 +184,7 @@
  *         register a OnErrorListener to look out for error notifications from
  *         the internal player engine.</li>
  *         <li>IllegalStateException is
- *         thrown to prevent programming errors such as calling {@link #prepare()},
+ *         thrown to prevent programming errors such as calling
  *         {@link #prepareAsync()}, {@link #setDataSource(DataSourceDesc)}, or
  *         {@code setPlaylist} methods in an invalid state. </li>
  *         </ul>
@@ -206,15 +206,11 @@
  *     <li>A MediaPlayer2 object must first enter the <em>Prepared</em> state
  *         before playback can be started.
  *         <ul>
- *         <li>There are two ways (synchronous vs.
- *         asynchronous) that the <em>Prepared</em> state can be reached:
- *         either a call to {@link #prepare()} (synchronous) which
- *         transfers the object to the <em>Prepared</em> state once the method call
- *         returns, or a call to {@link #prepareAsync()} (asynchronous) which
- *         first transfers the object to the <em>Preparing</em> state after the
+ *         <li>{@link #prepareAsync()} first transfers the object to the
+ *         <em>Preparing</em> state after the
  *         call returns (which occurs almost right way) while the internal
  *         player engine continues working on the rest of preparation work
- *         until the preparation work completes. When the preparation completes or when {@link #prepare()} call returns,
+ *         until the preparation work completes. When the preparation completes,
  *         the internal player engine then calls a user supplied callback method,
  *         onPrepared() of the EventCallback interface, if an
  *         EventCallback is registered beforehand via {@link
@@ -224,7 +220,7 @@
  *         of calling any method with side effect while a MediaPlayer2 object is
  *         in the <em>Preparing</em> state is undefined.</li>
  *         <li>An IllegalStateException is
- *         thrown if {@link #prepare()} or {@link #prepareAsync()} is called in
+ *         thrown if {@link #prepareAsync()} is called in
  *         any other state.</li>
  *         <li>While in the <em>Prepared</em> state, properties
  *         such as audio/sound volume, screenOnWhilePlaying, looping can be
@@ -395,7 +391,7 @@
  *     <td>{Error}</p></td>
  *     <td>Successful invoke of this method does not change the state. In order for the
  *         target audio attributes type to become effective, this method must be called before
- *         prepare() or prepareAsync().</p></td></tr>
+ *         prepareAsync().</p></td></tr>
  * <tr><td>setAudioSessionId </p></td>
  *     <td>{Idle} </p></td>
  *     <td>{Initialized, Prepared, Started, Paused, Stopped, PlaybackCompleted,
@@ -409,7 +405,7 @@
  *     <td>{Error}</p></td>
  *     <td>Successful invoke of this method does not change the state. In order for the
  *         target audio stream type to become effective, this method must be called before
- *         prepare() or prepareAsync().</p></td></tr>
+ *         prepareAsync().</p></td></tr>
  * <tr><td>setAuxEffectSendLevel </p></td>
  *     <td>any</p></td>
  *     <td>{} </p></td>
@@ -561,9 +557,12 @@
     private boolean mBypassInterruptionPolicy;
     private final CloseGuard mGuard = CloseGuard.get();
 
+    private final Object mPlLock = new Object();
     private List<DataSourceDesc> mPlaylist;
-    private int mPLCurrentIndex = 0;
-    private int mPLNextIndex = -1;
+    private int mPlCurrentIndex = 0;
+    private int mPlNextIndex = -1;
+    private int mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
+    private boolean mPlNextSourcePlayPending = false;
     private int mLoopingMode = LOOPING_MODE_NONE;
 
     // Modular DRM
@@ -605,6 +604,11 @@
         native_setup(new WeakReference<MediaPlayer2Impl>(this));
     }
 
+    private static final int NEXT_SOURCE_STATE_ERROR = -1;
+    private static final int NEXT_SOURCE_STATE_INIT = 0;
+    private static final int NEXT_SOURCE_STATE_PREPARING = 1;
+    private static final int NEXT_SOURCE_STATE_PREPARED = 2;
+
     /*
      * Update the MediaPlayer2Impl SurfaceTexture.
      * Call after setting a new display surface.
@@ -774,10 +778,13 @@
     @Override
     public void setDataSource(@NonNull DataSourceDesc dsd) throws IOException {
         Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
-        mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
-        mPlaylist.add(dsd);
-        mPLCurrentIndex = 0;
-        setDataSourcePriv(dsd);
+        synchronized (mPlLock) {
+            mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>(1));
+            mPlaylist.add(dsd);
+            mPlCurrentIndex = 0;
+            mPlNextIndex = -1;
+            handleDataSource(true /* isCurrent */, dsd);
+        }
     }
 
     /**
@@ -787,10 +794,12 @@
      */
     @Override
     public DataSourceDesc getCurrentDataSource() {
-        if (mPlaylist == null) {
-            return null;
+        synchronized (mPlLock) {
+            if (mPlaylist == null) {
+                return null;
+            }
+            return mPlaylist.get(mPlCurrentIndex);
         }
-        return mPlaylist.get(mPLCurrentIndex);
     }
 
     /**
@@ -826,11 +835,14 @@
             startIndex = pl.size() - 1;
         }
 
-        mPlaylist = Collections.synchronizedList(new ArrayList(pl));
-        mPLCurrentIndex = startIndex;
-        setDataSourcePriv(mPlaylist.get(startIndex));
-        // TODO: handle the preparation of next source in the play list.
-        // It should be processed after current source is prepared.
+        synchronized (mPlLock) {
+            mPlaylist = Collections.synchronizedList(new ArrayList(pl));
+            mPlCurrentIndex = startIndex;
+            handleDataSource(true /* isCurrent */, mPlaylist.get(startIndex));
+            // TODO: handle the preparation of next source in the play list.
+            // It should be processed after current source is prepared.
+            mPlNextIndex = getNextIndex_l();
+        }
     }
 
     /**
@@ -840,10 +852,12 @@
      */
     @Override
     public List<DataSourceDesc> getPlaylist() {
-        if (mPlaylist == null) {
-            return null;
+        synchronized (mPlLock) {
+            if (mPlaylist == null) {
+                return null;
+            }
+            return new ArrayList(mPlaylist);
         }
-        return new ArrayList(mPlaylist);
     }
 
     /**
@@ -855,19 +869,21 @@
      */
     @Override
     public void setCurrentPlaylistItem(int index) {
-        if (mPlaylist == null) {
-            throw new IllegalArgumentException("play list has not been set yet.");
-        }
-        if (index < 0 || index >= mPlaylist.size()) {
-            throw new IndexOutOfBoundsException("index is out of play list range.");
-        }
+        synchronized (mPlLock) {
+            if (mPlaylist == null) {
+                throw new IllegalArgumentException("play list has not been set yet.");
+            }
+            if (index < 0 || index >= mPlaylist.size()) {
+                throw new IndexOutOfBoundsException("index is out of play list range.");
+            }
 
-        if (index == mPLCurrentIndex) {
-            return;
-        }
+            if (index == mPlCurrentIndex) {
+                return;
+            }
 
-        // TODO: in playing state, stop current source and start to play source of index.
-        mPLCurrentIndex = index;
+            // TODO: in playing state, stop current source and start to play source of index.
+            mPlCurrentIndex = index;
+        }
     }
 
     /**
@@ -879,19 +895,21 @@
      */
     @Override
     public void setNextPlaylistItem(int index) {
-        if (mPlaylist == null) {
-            throw new IllegalArgumentException("play list has not been set yet.");
-        }
-        if (index < 0 || index >= mPlaylist.size()) {
-            throw new IndexOutOfBoundsException("index is out of play list range.");
-        }
+        synchronized (mPlLock) {
+            if (mPlaylist == null) {
+                throw new IllegalArgumentException("play list has not been set yet.");
+            }
+            if (index < 0 || index >= mPlaylist.size()) {
+                throw new IndexOutOfBoundsException("index is out of play list range.");
+            }
 
-        if (index == mPLNextIndex) {
-            return;
-        }
+            if (index == mPlNextIndex) {
+                return;
+            }
 
-        // TODO: prepare the new next-to-be-played DataSourceDesc
-        mPLNextIndex = index;
+            // TODO: prepare the new next-to-be-played DataSourceDesc
+            mPlNextIndex = index;
+        }
     }
 
     /**
@@ -901,7 +919,9 @@
      */
     @Override
     public int getCurrentPlaylistItemIndex() {
-        return mPLCurrentIndex;
+        synchronized (mPlLock) {
+            return mPlCurrentIndex;
+        }
     }
 
     /**
@@ -920,12 +940,15 @@
             && mode != LOOPING_MODE_SHUFFLE) {
             throw new IllegalArgumentException("mode is not supported.");
         }
-        mLoopingMode = mode;
-        if (mPlaylist == null) {
-            return;
-        }
 
-        // TODO: handle the new mode if necessary.
+        synchronized (mPlLock) {
+            mLoopingMode = mode;
+            if (mPlaylist == null) {
+                return;
+            }
+
+            // TODO: handle the new mode if necessary.
+        }
     }
 
     /**
@@ -935,7 +958,9 @@
      */
     @Override
     public int getLoopingMode() {
-        return mPLCurrentIndex;
+        synchronized (mPlLock) {
+            return mPlCurrentIndex;
+        }
     }
 
     /**
@@ -946,10 +971,12 @@
      */
     @Override
     public void movePlaylistItem(int indexFrom, int indexTo) {
-        if (mPlaylist == null) {
-            throw new IllegalArgumentException("play list has not been set yet.");
+        synchronized (mPlLock) {
+            if (mPlaylist == null) {
+                throw new IllegalArgumentException("play list has not been set yet.");
+            }
+            // TODO: move the DataSourceDesc from indexFrom to indexTo.
         }
-        // TODO: move the DataSourceDesc from indexFrom to indexTo.
     }
 
     /**
@@ -964,14 +991,16 @@
      */
     @Override
     public DataSourceDesc removePlaylistItem(int index) {
-        if (mPlaylist == null) {
-            throw new IllegalArgumentException("play list has not been set yet.");
-        }
+        synchronized (mPlLock) {
+            if (mPlaylist == null) {
+                throw new IllegalArgumentException("play list has not been set yet.");
+            }
 
-        DataSourceDesc oldDsd = mPlaylist.remove(index);
-        // TODO: if index == mPLCurrentIndex, stop current source and move to next one.
-        // if index == mPLNextIndex, prepare the new next-to-be-played source.
-        return oldDsd;
+            DataSourceDesc oldDsd = mPlaylist.remove(index);
+            // TODO: if index == mPlCurrentIndex, stop current source and move to next one.
+            // if index == mPlNextIndex, prepare the new next-to-be-played source.
+            return oldDsd;
+        }
     }
 
     /**
@@ -990,26 +1019,28 @@
     public void addPlaylistItem(int index, DataSourceDesc dsd) {
         Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
 
-        if (mPlaylist == null) {
-            if (index == 0) {
-                mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
-                mPlaylist.add(dsd);
-                mPLCurrentIndex = 0;
-                return;
+        synchronized (mPlLock) {
+            if (mPlaylist == null) {
+                if (index == 0) {
+                    mPlaylist = Collections.synchronizedList(new ArrayList<DataSourceDesc>());
+                    mPlaylist.add(dsd);
+                    mPlCurrentIndex = 0;
+                    return;
+                }
+                throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
             }
-            throw new IllegalArgumentException("index should be 0 for first DataSourceDesc.");
-        }
 
-        long id = dsd.getId();
-        for (DataSourceDesc pldsd : mPlaylist) {
-            if (id == pldsd.getId()) {
-                throw new IllegalArgumentException("Id of dsd already exists in the play list.");
+            long id = dsd.getId();
+            for (DataSourceDesc pldsd : mPlaylist) {
+                if (id == pldsd.getId()) {
+                    throw new IllegalArgumentException("Id of dsd already exists in the play list.");
+                }
             }
-        }
 
-        mPlaylist.add(index, dsd);
-        if (index <= mPLCurrentIndex) {
-            ++mPLCurrentIndex;
+            mPlaylist.add(index, dsd);
+            if (index <= mPlCurrentIndex) {
+                ++mPlCurrentIndex;
+            }
         }
     }
 
@@ -1036,42 +1067,62 @@
         Preconditions.checkNotNull(mPlaylist, "the play list cannot be null");
 
         long id = dsd.getId();
-        for (int i = 0; i < mPlaylist.size(); ++i) {
-            if (i == index) {
-                continue;
+        synchronized (mPlLock) {
+            for (int i = 0; i < mPlaylist.size(); ++i) {
+                if (i == index) {
+                    continue;
+                }
+                if (id == mPlaylist.get(i).getId()) {
+                    throw new IllegalArgumentException(
+                            "Id of dsd already exists in the play list.");
+                }
             }
-            if (id == mPlaylist.get(i).getId()) {
-                throw new IllegalArgumentException("Id of dsd already exists in the play list.");
-            }
-        }
 
-        // TODO: if needed, stop playback of current source, and start new dsd.
-        DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
-        return mPlaylist.set(index, dsd);
+            // TODO: if needed, stop playback of current source, and start new dsd.
+            DataSourceDesc oldDsd = mPlaylist.set(index, dsd);
+            return mPlaylist.set(index, dsd);
+        }
     }
 
-    private void setDataSourcePriv(@NonNull DataSourceDesc dsd) throws IOException {
+    // Called with mPlLock acquired.
+    // TODO: support all looping modes
+    private int getNextIndex_l() {
+        if (mPlaylist.size() <= 1) {
+            return -1;
+        }
+        int index = mPlCurrentIndex + 1;
+        if (index >= mPlaylist.size()) {
+            index = 0;
+        }
+        return index;
+    }
+
+    private void handleDataSource(boolean isCurrent, @NonNull DataSourceDesc dsd)
+            throws IOException {
         Preconditions.checkNotNull(dsd, "the DataSourceDesc cannot be null");
 
         switch (dsd.getType()) {
             case DataSourceDesc.TYPE_CALLBACK:
-                setDataSourcePriv(dsd.getId(),
-                                  dsd.getMedia2DataSource());
+                handleDataSource(isCurrent,
+                                 dsd.getId(),
+                                 dsd.getMedia2DataSource());
                 break;
 
             case DataSourceDesc.TYPE_FD:
-                setDataSourcePriv(dsd.getId(),
-                                  dsd.getFileDescriptor(),
-                                  dsd.getFileDescriptorOffset(),
-                                  dsd.getFileDescriptorLength());
+                handleDataSource(isCurrent,
+                                 dsd.getId(),
+                                 dsd.getFileDescriptor(),
+                                 dsd.getFileDescriptorOffset(),
+                                 dsd.getFileDescriptorLength());
                 break;
 
             case DataSourceDesc.TYPE_URI:
-                setDataSourcePriv(dsd.getId(),
-                                  dsd.getUriContext(),
-                                  dsd.getUri(),
-                                  dsd.getUriHeaders(),
-                                  dsd.getUriCookies());
+                handleDataSource(isCurrent,
+                                 dsd.getId(),
+                                 dsd.getUriContext(),
+                                 dsd.getUri(),
+                                 dsd.getUriHeaders(),
+                                 dsd.getUriCookies());
                 break;
 
             default:
@@ -1098,66 +1149,59 @@
      * @throws NullPointerException     if context or uri is null
      * @throws IOException              if uri has a file scheme and an I/O error occurs
      */
-    private void setDataSourcePriv(long srcId, @NonNull Context context, @NonNull Uri uri,
+    private void handleDataSource(
+            boolean isCurrent, long srcId,
+            @NonNull Context context, @NonNull Uri uri,
             @Nullable Map<String, String> headers, @Nullable List<HttpCookie> cookies)
             throws IOException {
-        if (context == null) {
-            throw new NullPointerException("context param can not be null.");
-        }
-
-        if (uri == null) {
-            throw new NullPointerException("uri param can not be null.");
-        }
-
-        if (cookies != null) {
-            CookieHandler cookieHandler = CookieHandler.getDefault();
-            if (cookieHandler != null && !(cookieHandler instanceof CookieManager)) {
-                throw new IllegalArgumentException("The cookie handler has to be of CookieManager "
-                        + "type when cookies are provided.");
-            }
-        }
-
         // The context and URI usually belong to the calling user. Get a resolver for that user
         // and strip out the userId from the URI if present.
         final ContentResolver resolver = context.getContentResolver();
         final String scheme = uri.getScheme();
         final String authority = ContentProvider.getAuthorityWithoutUserId(uri.getAuthority());
         if (ContentResolver.SCHEME_FILE.equals(scheme)) {
-            setDataSourcePriv(srcId, uri.getPath(), null, null);
+            handleDataSource(isCurrent, srcId, uri.getPath(), null, null);
             return;
-        } else if (ContentResolver.SCHEME_CONTENT.equals(scheme)
+        }
+
+        if (ContentResolver.SCHEME_CONTENT.equals(scheme)
                 && Settings.AUTHORITY.equals(authority)) {
             // Try cached ringtone first since the actual provider may not be
             // encryption aware, or it may be stored on CE media storage
             final int type = RingtoneManager.getDefaultType(uri);
             final Uri cacheUri = RingtoneManager.getCacheForType(type, context.getUserId());
             final Uri actualUri = RingtoneManager.getActualDefaultRingtoneUri(context, type);
-            if (attemptDataSource(srcId, resolver, cacheUri)) {
+            if (attemptDataSource(isCurrent, srcId, resolver, cacheUri)) {
                 return;
-            } else if (attemptDataSource(srcId, resolver, actualUri)) {
-                return;
-            } else {
-                setDataSourcePriv(srcId, uri.toString(), headers, cookies);
             }
+            if (attemptDataSource(isCurrent, srcId, resolver, actualUri)) {
+                return;
+            }
+            handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
         } else {
             // Try requested Uri locally first, or fallback to media server
-            if (attemptDataSource(srcId, resolver, uri)) {
+            if (attemptDataSource(isCurrent, srcId, resolver, uri)) {
                 return;
-            } else {
-                setDataSourcePriv(srcId, uri.toString(), headers, cookies);
             }
+            handleDataSource(isCurrent, srcId, uri.toString(), headers, cookies);
         }
     }
 
-    private boolean attemptDataSource(long srcId, ContentResolver resolver, Uri uri) {
+    private boolean attemptDataSource(
+            boolean isCurrent, long srcId, ContentResolver resolver, Uri uri) {
         try (AssetFileDescriptor afd = resolver.openAssetFileDescriptor(uri, "r")) {
             if (afd.getDeclaredLength() < 0) {
-                setDataSourcePriv(srcId, afd.getFileDescriptor(), 0, DataSourceDesc.LONG_MAX);
+                handleDataSource(isCurrent,
+                                 srcId,
+                                 afd.getFileDescriptor(),
+                                 0,
+                                 DataSourceDesc.LONG_MAX);
             } else {
-                setDataSourcePriv(srcId,
-                                  afd.getFileDescriptor(),
-                                  afd.getStartOffset(),
-                                  afd.getDeclaredLength());
+                handleDataSource(isCurrent,
+                                 srcId,
+                                 afd.getFileDescriptor(),
+                                 afd.getStartOffset(),
+                                 afd.getDeclaredLength());
             }
             return true;
         } catch (NullPointerException | SecurityException | IOException ex) {
@@ -1166,10 +1210,10 @@
         }
     }
 
-    private void setDataSourcePriv(
-            long srcId, String path, Map<String, String> headers, List<HttpCookie> cookies)
-            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException
-    {
+    private void handleDataSource(
+            boolean isCurrent, long srcId,
+            String path, Map<String, String> headers, List<HttpCookie> cookies)
+            throws IOException {
         String[] keys = null;
         String[] values = null;
 
@@ -1184,19 +1228,20 @@
                 ++i;
             }
         }
-        setDataSourcePriv(srcId, path, keys, values, cookies);
+        handleDataSource(isCurrent, srcId, path, keys, values, cookies);
     }
 
-    private void setDataSourcePriv(long srcId, String path, String[] keys, String[] values,
-            List<HttpCookie> cookies)
-            throws IOException, IllegalArgumentException, SecurityException, IllegalStateException {
+    private void handleDataSource(boolean isCurrent, long srcId,
+            String path, String[] keys, String[] values, List<HttpCookie> cookies)
+            throws IOException {
         final Uri uri = Uri.parse(path);
         final String scheme = uri.getScheme();
         if ("file".equals(scheme)) {
             path = uri.getPath();
         } else if (scheme != null) {
             // handle non-file sources
-            nativeSetDataSource(
+            nativeHandleDataSourceUrl(
+                isCurrent,
                 srcId,
                 Media2HTTPService.createHTTPService(path, cookies),
                 path,
@@ -1209,16 +1254,17 @@
         if (file.exists()) {
             FileInputStream is = new FileInputStream(file);
             FileDescriptor fd = is.getFD();
-            setDataSourcePriv(srcId, fd, 0, DataSourceDesc.LONG_MAX);
+            handleDataSource(isCurrent, srcId, fd, 0, DataSourceDesc.LONG_MAX);
             is.close();
         } else {
-            throw new IOException("setDataSourcePriv failed.");
+            throw new IOException("handleDataSource failed.");
         }
     }
 
-    private native void nativeSetDataSource(
-        long srcId, Media2HTTPService httpService, String path, String[] keys, String[] values)
-        throws IOException, IllegalArgumentException, SecurityException, IllegalStateException;
+    private native void nativeHandleDataSourceUrl(
+            boolean isCurrent, long srcId,
+            Media2HTTPService httpService, String path, String[] keys, String[] values)
+            throws IOException;
 
     /**
      * Sets the data source (FileDescriptor) to use. The FileDescriptor must be
@@ -1229,53 +1275,92 @@
      * @throws IllegalArgumentException if fd is not a valid FileDescriptor
      * @throws IOException if fd can not be read
      */
-    private void setDataSourcePriv(long srcId, FileDescriptor fd, long offset, long length)
-            throws IOException {
-        _setDataSource(srcId, fd, offset, length);
+    private void handleDataSource(
+            boolean isCurrent, long srcId,
+            FileDescriptor fd, long offset, long length) throws IOException {
+        nativeHandleDataSourceFD(isCurrent, srcId, fd, offset, length);
     }
 
-    private native void _setDataSource(long srcId, FileDescriptor fd, long offset, long length)
-            throws IOException;
+    private native void nativeHandleDataSourceFD(boolean isCurrent, long srcId,
+            FileDescriptor fd, long offset, long length) throws IOException;
 
     /**
      * @throws IllegalStateException if it is called in an invalid state
      * @throws IllegalArgumentException if dataSource is not a valid Media2DataSource
      */
-    private void setDataSourcePriv(long srcId, Media2DataSource dataSource) {
-        _setDataSource(srcId, dataSource);
+    private void handleDataSource(boolean isCurrent, long srcId, Media2DataSource dataSource) {
+        nativeHandleDataSourceCallback(isCurrent, srcId, dataSource);
     }
 
-    private native void _setDataSource(long srcId, Media2DataSource dataSource);
+    private native void nativeHandleDataSourceCallback(
+            boolean isCurrent, long srcId, Media2DataSource dataSource);
 
-    /**
-     * Prepares the player for playback, synchronously.
-     *
-     * After setting the datasource and the display surface, you need to either
-     * call prepare() or prepareAsync(). For files, it is OK to call prepare(),
-     * which blocks until MediaPlayer2 is ready for playback.
-     *
-     * @throws IOException if source can not be accessed
-     * @throws IllegalStateException if it is called in an invalid state
-     * @hide
-     */
-    @Override
-    public void prepare() throws IOException {
-        _prepare();
-        scanInternalSubtitleTracks();
+    // This function shall be called with |mPlLock| acquired.
+    private void prepareNextDataSource_l() {
+        if (mPlNextIndex < 0 || mPlNextSourceState != NEXT_SOURCE_STATE_INIT) {
+            // There is no next source or it's in preparing or prepared state.
+            return;
+        }
 
-        // DrmInfo, if any, has been resolved by now.
-        synchronized (mDrmLock) {
-            mDrmInfoResolved = true;
+        try {
+            mPlNextSourceState = NEXT_SOURCE_STATE_PREPARING;
+            handleDataSource(false /* isCurrent */, mPlaylist.get(mPlNextIndex));
+        } catch (Exception e) {
+            Message msg2 = mEventHandler.obtainMessage(
+                    MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
+            final long nextSrcId = mPlaylist.get(mPlNextIndex).getId();
+            mEventHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    mEventHandler.handleMessage(msg2, nextSrcId);
+                }
+            });
         }
     }
 
-    private native void _prepare() throws IOException, IllegalStateException;
+    // This function shall be called with |mPlLock| acquired.
+    private void playNextDataSource_l() {
+        if (mPlNextIndex < 0) {
+            return;
+        }
+
+        if (mPlNextSourceState == NEXT_SOURCE_STATE_PREPARED) {
+            // Switch to next source only when it's in prepared state.
+            mPlCurrentIndex = mPlNextIndex;
+            mPlNextIndex = getNextIndex_l();
+            mPlNextSourceState = NEXT_SOURCE_STATE_INIT;
+            mPlNextSourcePlayPending = false;
+
+            long srcId = mPlaylist.get(mPlCurrentIndex).getId();
+            try {
+                nativePlayNextDataSource(srcId);
+            } catch (Exception e) {
+                Message msg2 = mEventHandler.obtainMessage(
+                        MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
+                mEventHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        mEventHandler.handleMessage(msg2, srcId);
+                    }
+                });
+            }
+
+            // Wait for MEDIA2_INFO_STARTED_AS_NEXT to prepare next source.
+        } else {
+            if (mPlNextSourceState == NEXT_SOURCE_STATE_INIT) {
+                prepareNextDataSource_l();
+            }
+            mPlNextSourcePlayPending = true;
+        }
+    }
+
+    private native void nativePlayNextDataSource(long srcId);
 
     /**
      * Prepares the player for playback, asynchronously.
      *
      * After setting the datasource and the display surface, you need to either
-     * call prepare() or prepareAsync(). For streams, you should call prepareAsync(),
+     * call prepareAsync(). For streams, you should call prepareAsync(),
      * which returns immediately, rather than blocking until enough data has been
      * buffered.
      *
@@ -1925,7 +2010,7 @@
     /**
      * Resets the MediaPlayer2 to its uninitialized state. After calling
      * this method, you will have to initialize it again by setting the
-     * data source and calling prepare().
+     * data source and calling prepareAsync().
      */
     @Override
     public void reset() {
@@ -2000,7 +2085,7 @@
     /**
      * Sets the audio attributes for this MediaPlayer2.
      * See {@link AudioAttributes} for how to build and configure an instance of this class.
-     * You must call this method before {@link #prepare()} or {@link #prepareAsync()} in order
+     * You must call this method before {@link #prepareAsync()} in order
      * for the audio attributes to become effective thereafter.
      * @param attributes a non-null set of audio attributes
      * @throws IllegalArgumentException if the attributes are null or invalid.
@@ -3089,6 +3174,19 @@
                     sendMessage(msg2);
                 }
 
+                synchronized (mPlLock) {
+                    Log.i(TAG, "MEDIA_PREPARED: srcId=" + srcId
+                            + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
+                    if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+                        prepareNextDataSource_l();
+                    } else if (mPlNextIndex >= 0 && srcId == mPlaylist.get(mPlNextIndex).getId()) {
+                        mPlNextSourceState = NEXT_SOURCE_STATE_PREPARED;
+                        if (mPlNextSourcePlayPending) {
+                            playNextDataSource_l();
+                        }
+                    }
+                }
+
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
@@ -3127,6 +3225,14 @@
                 return;
 
             case MEDIA_PLAYBACK_COMPLETE:
+                synchronized (mPlLock) {
+                    if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+                        Log.i(TAG, "MEDIA_PLAYBACK_COMPLETE: srcId=" + srcId
+                                + ", currentIndex=" + mPlCurrentIndex + ", nextIndex=" + mPlNextIndex);
+                        playNextDataSource_l();
+                    }
+                }
+
                 synchronized (mEventCbLock) {
                     for (Pair<Executor, EventCallback> cb : mEventCallbackRecords) {
                         cb.first.execute(() -> cb.second.onInfo(
@@ -3209,6 +3315,12 @@
 
             case MEDIA_INFO:
                 switch (msg.arg1) {
+                    case MEDIA_INFO_STARTED_AS_NEXT:
+                        if (mPlCurrentIndex >= 0 && srcId == mPlaylist.get(mPlCurrentIndex).getId()) {
+                            prepareNextDataSource_l();
+                        }
+                        break;
+
                     case MEDIA_INFO_VIDEO_TRACK_LAGGING:
                         Log.i(TAG, "Info (" + msg.arg1 + "," + msg.arg2 + ")");
                         break;
@@ -3517,7 +3629,7 @@
     /**
      * Retrieves the DRM Info associated with the current source
      *
-     * @throws IllegalStateException if called before prepare()
+     * @throws IllegalStateException if called before prepareAsync()
      */
     @Override
     public DrmInfo getDrmInfo() {
@@ -3568,7 +3680,7 @@
      * @param uuid The UUID of the crypto scheme. If not known beforehand, it can be retrieved
      * from the source through {@code getDrmInfo} or registering a {@code onDrmInfoListener}.
      *
-     * @throws IllegalStateException              if called before prepare(), or the DRM was
+     * @throws IllegalStateException              if called before prepareAsync(), or the DRM was
      *                                            prepared already
      * @throws UnsupportedSchemeException         if the crypto scheme is not supported
      * @throws ResourceBusyException              if required DRM resources are in use
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 823410f..9ad5cd9 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -17,6 +17,7 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.app.ActivityThread;
 import android.hardware.Camera;
@@ -278,6 +279,7 @@
          * third-party applications.
          * </p>
          */
+        @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
         public static final int REMOTE_SUBMIX = 8;
 
         /** Microphone audio source tuned for unprocessed (raw) sound if available, behaves like
@@ -303,6 +305,7 @@
          * @hide
          */
         @SystemApi
+        @RequiresPermission(android.Manifest.permission.CAPTURE_AUDIO_HOTWORD)
         public static final int HOTWORD = 1999;
     }
 
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 2190635..343bbda 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -400,6 +400,7 @@
                 new AudioAttributes.Builder()
                         .setInternalCapturePreset(MediaRecorder.AudioSource.REMOTE_SUBMIX)
                         .addTag(addressForTag(mix))
+                        .addTag(AudioRecord.SUBMIX_FIXED_VOLUME)
                         .build(),
                 mixFormat,
                 AudioRecord.getMinBufferSize(mix.getFormat().getSampleRate(),
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 51bc330..5a0081a 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -273,9 +273,9 @@
 }
 
 static void
-android_media_MediaPlayer2_setDataSourceAndHeaders(
-        JNIEnv *env, jobject thiz, jlong srcId, jobject httpServiceObj, jstring path,
-        jobjectArray keys, jobjectArray values) {
+android_media_MediaPlayer2_handleDataSourceUrl(
+        JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+        jobject httpServiceObj, jstring path, jobjectArray keys, jobjectArray values) {
 
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL) {
@@ -292,10 +292,10 @@
     if (tmp == NULL) {  // Out of memory
         return;
     }
-    ALOGV("setDataSourceAndHeaders: path %s, srcId %lld", tmp, (long long)srcId);
+    ALOGV("handleDataSourceUrl: path %s, srcId %lld", tmp, (long long)srcId);
 
     if (strncmp(tmp, "content://", 10) == 0) {
-        ALOGE("setDataSourceAndHeaders: content scheme is not supported in native code");
+        ALOGE("handleDataSourceUrl: content scheme is not supported in native code");
         jniThrowException(env, "java/io/IOException",
                           "content scheme is not supported in native code");
         return;
@@ -321,14 +321,20 @@
     }
     dsd->mHttpService = httpService;
 
-    process_media_player_call(
-            env, thiz, mp->setDataSource(dsd), "java/io/IOException",
-            "setDataSourceAndHeaders failed." );
+    status_t err;
+    if (isCurrent) {
+        err = mp->setDataSource(dsd);
+    } else {
+        err = mp->prepareNextDataSource(dsd);
+    }
+    process_media_player_call(env, thiz, err,
+            "java/io/IOException", "handleDataSourceUrl failed." );
 }
 
 static void
-android_media_MediaPlayer2_setDataSourceFD(
-    JNIEnv *env, jobject thiz, jlong srcId, jobject fileDescriptor, jlong offset, jlong length)
+android_media_MediaPlayer2_handleDataSourceFD(
+    JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId,
+    jobject fileDescriptor, jlong offset, jlong length)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -341,14 +347,14 @@
         return;
     }
     int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    ALOGV("setDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
+    ALOGV("handleDataSourceFD: srcId=%lld, fd=%d (%s), offset=%lld, length=%lld",
           (long long)srcId, fd, nameForFd(fd).c_str(), (long long)offset, (long long)length);
 
     struct stat sb;
     int ret = fstat(fd, &sb);
     if (ret != 0) {
-        ALOGE("setDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
-        jniThrowException(env, "java/io/IOException", "setDataSourceFD failed fstat");
+        ALOGE("handleDataSourceFD: fstat(%d) failed: %d, %s", fd, ret, strerror(errno));
+        jniThrowException(env, "java/io/IOException", "handleDataSourceFD failed fstat");
         return;
     }
 
@@ -359,14 +365,14 @@
     ALOGV("st_size = %llu", static_cast<unsigned long long>(sb.st_size));
 
     if (offset >= sb.st_size) {
-        ALOGE("setDataSourceFD: offset is out of range");
+        ALOGE("handleDataSourceFD: offset is out of range");
         jniThrowException(env, "java/lang/IllegalArgumentException",
-                          "setDataSourceFD failed, offset is out of range.");
+                          "handleDataSourceFD failed, offset is out of range.");
         return;
     }
     if (offset + length > sb.st_size) {
         length = sb.st_size - offset;
-        ALOGV("setDataSourceFD: adjusted length = %lld", (long long)length);
+        ALOGV("handleDataSourceFD: adjusted length = %lld", (long long)length);
     }
 
     sp<DataSourceDesc> dsd = new DataSourceDesc();
@@ -375,13 +381,20 @@
     dsd->mFD = fd;
     dsd->mFDOffset = offset;
     dsd->mFDLength = length;
-    process_media_player_call(env, thiz, mp->setDataSource(dsd),
-                              "java/io/IOException", "setDataSourceFD failed." );
+
+    status_t err;
+    if (isCurrent) {
+        err = mp->setDataSource(dsd);
+    } else {
+        err = mp->prepareNextDataSource(dsd);
+    }
+    process_media_player_call(env, thiz, err,
+            "java/io/IOException", "handleDataSourceFD failed." );
 }
 
 static void
-android_media_MediaPlayer2_setDataSourceCallback(
-    JNIEnv *env, jobject thiz, jlong srcId, jobject dataSource)
+android_media_MediaPlayer2_handleDataSourceCallback(
+    JNIEnv *env, jobject thiz, jboolean isCurrent, jlong srcId, jobject dataSource)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
     if (mp == NULL ) {
@@ -398,8 +411,15 @@
     dsd->mId = srcId;
     dsd->mType = DataSourceDesc::TYPE_CALLBACK;
     dsd->mCallbackSource = callbackDataSource;
-    process_media_player_call(env, thiz, mp->setDataSource(dsd),
-                              "java/lang/RuntimeException", "setDataSourceCallback failed." );
+
+    status_t err;
+    if (isCurrent) {
+        err = mp->setDataSource(dsd);
+    } else {
+        err = mp->prepareNextDataSource(dsd);
+    }
+    process_media_player_call(env, thiz, err,
+            "java/lang/RuntimeException", "handleDataSourceCallback failed." );
 }
 
 static sp<ANativeWindowWrapper>
@@ -503,20 +523,16 @@
 }
 
 static void
-android_media_MediaPlayer2_prepare(JNIEnv *env, jobject thiz)
+android_media_MediaPlayer2_playNextDataSource(JNIEnv *env, jobject thiz, jlong srcId)
 {
     sp<MediaPlayer2> mp = getMediaPlayer(env, thiz);
-    if (mp == NULL ) {
+    if (mp == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException", NULL);
         return;
     }
 
-    // Handle the case where the display surface was set before the mp was
-    // initialized. We try again to make it stick.
-    sp<ANativeWindowWrapper> st = getVideoSurfaceTexture(env, thiz);
-    mp->setVideoSurfaceTexture(st);
-
-    process_media_player_call( env, thiz, mp->prepare(), "java/io/IOException", "Prepare failed." );
+    process_media_player_call(env, thiz, mp->playNextDataSource((int64_t)srcId),
+            "java/io/IOException", "playNextDataSource failed." );
 }
 
 static void
@@ -1449,18 +1465,25 @@
 
 static const JNINativeMethod gMethods[] = {
     {
-        "nativeSetDataSource",
-        "(JLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
+        "nativeHandleDataSourceUrl",
+        "(ZJLandroid/media/Media2HTTPService;Ljava/lang/String;[Ljava/lang/String;"
         "[Ljava/lang/String;)V",
-        (void *)android_media_MediaPlayer2_setDataSourceAndHeaders
+        (void *)android_media_MediaPlayer2_handleDataSourceUrl
     },
-
-    {"_setDataSource",      "(JLjava/io/FileDescriptor;JJ)V",    (void *)android_media_MediaPlayer2_setDataSourceFD},
-    {"_setDataSource",      "(JLandroid/media/Media2DataSource;)V",(void *)android_media_MediaPlayer2_setDataSourceCallback },
+    {
+        "nativeHandleDataSourceFD",
+        "(ZJLjava/io/FileDescriptor;JJ)V",
+        (void *)android_media_MediaPlayer2_handleDataSourceFD
+    },
+    {
+        "nativeHandleDataSourceCallback",
+        "(ZJLandroid/media/Media2DataSource;)V",
+        (void *)android_media_MediaPlayer2_handleDataSourceCallback
+    },
+    {"nativePlayNextDataSource", "(J)V",                        (void *)android_media_MediaPlayer2_playNextDataSource},
     {"_setVideoSurface",    "(Landroid/view/Surface;)V",        (void *)android_media_MediaPlayer2_setVideoSurface},
     {"getBufferingParams", "()Landroid/media/BufferingParams;", (void *)android_media_MediaPlayer2_getBufferingParams},
     {"setBufferingParams", "(Landroid/media/BufferingParams;)V", (void *)android_media_MediaPlayer2_setBufferingParams},
-    {"_prepare",            "()V",                              (void *)android_media_MediaPlayer2_prepare},
     {"prepareAsync",        "()V",                              (void *)android_media_MediaPlayer2_prepareAsync},
     {"_start",              "()V",                              (void *)android_media_MediaPlayer2_start},
     {"_stop",               "()V",                              (void *)android_media_MediaPlayer2_stop},
diff --git a/telephony/java/android/telephony/OWNERS b/packages/CarrierDefaultApp/OWNERS
similarity index 92%
rename from telephony/java/android/telephony/OWNERS
rename to packages/CarrierDefaultApp/OWNERS
index 68dedce..7057ce6 100644
--- a/telephony/java/android/telephony/OWNERS
+++ b/packages/CarrierDefaultApp/OWNERS
@@ -1,14 +1,12 @@
-set noparent
-
-amitmahajan@google.com
+tgunn@google.com
 breadley@google.com
-fionaxu@google.com
-jackyu@google.com
 hallliu@google.com
 rgreenwalt@google.com
-tgunn@google.com
-jminjie@google.com
 mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
 shuoq@google.com
-refuhoo@google.com
-
+refuhoo@google.com
\ No newline at end of file
diff --git a/packages/DefaultContainerService/AndroidManifest.xml b/packages/DefaultContainerService/AndroidManifest.xml
index e399fb1..9f54652 100644
--- a/packages/DefaultContainerService/AndroidManifest.xml
+++ b/packages/DefaultContainerService/AndroidManifest.xml
@@ -6,9 +6,6 @@
     <uses-permission android:name="android.permission.ASEC_DESTROY"/>
     <uses-permission android:name="android.permission.ASEC_MOUNT_UNMOUNT"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-    <!-- Used to improve MeasureUtils performance on emulated storage, and to
-         view storage for all users -->
-    <uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE" />
     <uses-permission android:name="android.permission.ACCESS_CACHE_FILESYSTEM" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
 
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..d7f9449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..7c65703
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..eea819a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..504ceb7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..8e7d8cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..456a68f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..fb854ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..75d184a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..9e0af28
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..7c00bd5d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..81b4466
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..724aa9e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..7ba0d1b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..a175ccb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..45ce1d4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..6da0c9e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..71e8959
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..bb7ae26
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..32b9ded
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..ed1949c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..d888869
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..dc3b25c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..d4e5a94
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..0e693f7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..0757799
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..4f07ec1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..ba5b457
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..a55ea1d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..407ef28
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..39cfbf2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..a7fd3a6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..f2a1255
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
new file mode 100644
index 0000000..5a7eec6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
new file mode 100644
index 0000000..f7abb54
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
new file mode 100644
index 0000000..a1f44dc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
new file mode 100644
index 0000000..175a9ae
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
new file mode 100644
index 0000000..0fb93ca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
new file mode 100644
index 0000000..1052940
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
Binary files differ
diff --git a/packages/SystemUI/res/layout/quick_settings_header.xml b/packages/SystemUI/res/layout/quick_settings_header.xml
deleted file mode 100644
index 43197c4..0000000
--- a/packages/SystemUI/res/layout/quick_settings_header.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright (C) 2018 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
-  -->
-<com.android.systemui.qs.QSTooltipView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="@dimen/qs_header_tooltip_height"
-    android:alpha="0"
-    android:gravity="center_horizontal|bottom"
-    android:visibility="invisible">
-
-    <TextView
-        android:id="@+id/header_text"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:text="@string/quick_settings_header_onboarding_text"
-        android:textAppearance="@style/TextAppearance.QS.TileLabel"
-        android:textColor="?android:attr/colorAccent" />
-
-</com.android.systemui.qs.QSTooltipView>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 13ca114..a5e37d5 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -40,7 +40,7 @@
     <dimen name="battery_detail_graph_space_top">27dp</dimen>
     <dimen name="battery_detail_graph_space_bottom">27dp</dimen>
 
-    <dimen name="qs_tile_margin_top">32dp</dimen>
+    <dimen name="qs_tile_margin_top">16dp</dimen>
     <dimen name="qs_brightness_padding_top">6dp</dimen>
     <dimen name="qs_detail_margin_top">28dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index 7541b0e..9197bb5 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -30,7 +30,7 @@
         <item>com.google.android.apps.mediashell/.settings.CastSettingsActivity</item>
         <item>com.google.android.katniss.setting/.SpeechSettingsActivity</item>
         <item>com.google.android.katniss.setting/.SearchSettingsActivity</item>
-        <item>com.google.android.gsf.notouch/.UsageDiagnosticsSettingActivity</item>
+        <item>com.google.android.tungsten.setupwraith/.settings.usage.UsageDiagnosticsSettingActivity</item>
         <item>com.google.android.tvlauncher/.notifications.NotificationsSidePanelActivity</item>
     </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index bc828ff..d17cd21 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -290,7 +290,7 @@
 
     <dimen name="qs_tile_height">106dp</dimen>
     <dimen name="qs_tile_margin">19dp</dimen>
-    <dimen name="qs_tile_margin_top">32dp</dimen>
+    <dimen name="qs_tile_margin_top">16dp</dimen>
     <dimen name="qs_quick_tile_size">48dp</dimen>
     <dimen name="qs_quick_tile_padding">12dp</dimen>
     <dimen name="qs_header_gear_translation">16dp</dimen>
@@ -309,7 +309,6 @@
     <dimen name="qs_tile_padding_bottom">16dp</dimen>
     <dimen name="qs_tile_spacing">4dp</dimen>
     <dimen name="qs_panel_padding_bottom">0dp</dimen>
-    <dimen name="qs_panel_padding_top">32dp</dimen>
     <dimen name="qs_detail_header_height">56dp</dimen>
     <dimen name="qs_detail_header_padding">0dp</dimen>
     <dimen name="qs_detail_image_width">56dp</dimen>
@@ -334,9 +333,6 @@
     <dimen name="qs_detail_item_icon_width">32dp</dimen>
     <dimen name="qs_detail_item_icon_marginStart">0dp</dimen>
     <dimen name="qs_detail_item_icon_marginEnd">20dp</dimen>
-    <dimen name="qs_header_padding_start">16dp</dimen>
-    <dimen name="qs_header_padding_end">24dp</dimen>
-    <dimen name="qs_header_tooltip_height">32dp</dimen>
     <dimen name="qs_footer_padding_start">16dp</dimen>
     <dimen name="qs_footer_padding_end">24dp</dimen>
     <dimen name="qs_footer_icon_size">16dp</dimen>
@@ -924,15 +920,16 @@
     <integer name="wireless_charging_fade_duration">200</integer>
 
     <!-- Wired charging on AOD, text animation duration -->
-    <integer name="wired_charging_aod_text_animation_duration_down">500</integer>
+    <integer name="wired_charging_keyguard_text_animation_duration_down">500</integer>
     <!-- Wired charging on AOD, text animation duration -->
-    <integer name="wired_charging_aod_text_animation_duration_up">300</integer>
+    <integer name="wired_charging_keyguard_text_animation_duration_up">300</integer>
     <!-- Wired charging on AOD, text animation distance -->
-    <integer name="wired_charging_aod_text_animation_distance">-30</integer>
+    <integer name="wired_charging_keyguard_text_animation_distance">-30</integer>
 
     <!-- Logout button -->
     <dimen name="logout_button_layout_height">32dp</dimen>
     <dimen name="logout_button_padding_horizontal">16dp</dimen>
     <dimen name="logout_button_margin_bottom">12dp</dimen>
     <dimen name="logout_button_corner_radius">2dp</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 86cab22..8c59e75 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -666,8 +666,6 @@
     <!-- Textual description of Ethernet connections -->
     <string name="ethernet_label">Ethernet</string>
 
-    <!-- QuickSettings: Onboarding text that introduces users to long press on an option in order to view the option's menu in Settings [CHAR LIMIT=NONE] -->
-    <string name="quick_settings_header_onboarding_text">Press &amp; hold on the icons for more options</string>
     <!-- QuickSettings: Do not disturb [CHAR LIMIT=NONE] -->
     <string name="quick_settings_dnd_label">Do not disturb</string>
     <!-- QuickSettings: Do not disturb - Priority only [CHAR LIMIT=NONE] -->
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 8b57740..adb4e33 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -47,7 +47,6 @@
         Key.QS_INVERT_COLORS_ADDED,
         Key.QS_WORK_ADDED,
         Key.QS_NIGHTDISPLAY_ADDED,
-        Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
         Key.SEEN_MULTI_USER,
         Key.NUM_APPS_LAUNCHED,
         Key.HAS_SEEN_RECENTS_ONBOARDING,
@@ -77,11 +76,6 @@
         String QS_WORK_ADDED = "QsWorkAdded";
         @Deprecated
         String QS_NIGHTDISPLAY_ADDED = "QsNightDisplayAdded";
-        /**
-         * Used for tracking how many times the user has seen the long press tooltip in the Quick
-         * Settings panel.
-         */
-        String QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT = "QsLongPressTooltipShownCount";
         String SEEN_MULTI_USER = "HasSeenMultiUser";
         String NUM_APPS_LAUNCHED = "NumAppsLaunched";
         String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding";
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIService.java b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
index ddf0bd0..bb82a54 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIService.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIService.java
@@ -28,6 +28,8 @@
 import java.io.PrintWriter;
 
 import com.android.internal.os.BinderInternal;
+import com.android.systemui.plugins.PluginManager;
+import com.android.systemui.plugins.PluginManagerImpl;
 
 public class SystemUIService extends Service {
 
@@ -70,6 +72,10 @@
                 pw.println("dumping service: " + ui.getClass().getName());
                 ui.dump(fd, pw, args);
             }
+            if (Build.IS_DEBUGGABLE) {
+                pw.println("dumping plugins:");
+                ((PluginManagerImpl) Dependency.get(PluginManager.class)).dump(fd, pw, args);
+            }
         } else {
             String svc = args[0];
             for (SystemUI ui: services) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 34d3928..aa26419 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -59,6 +59,12 @@
     }
 
     @Override
+    public void onDestroy() {
+        Dependency.get(PluginManager.class).removePluginListener(this);
+        super.onDestroy();
+    }
+
+    @Override
     public void onPluginConnected(DozeServicePlugin plugin, Context pluginContext) {
         mDozePlugin = plugin;
         mDozePlugin.setDozeRequester(this);
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
index 82c0128..d5541e9 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -168,6 +168,12 @@
         return false;
     }
 
+    @Override
+    public String toString() {
+        return String.format("%s@%s (action=%s)",
+                getClass().getSimpleName(), hashCode(), mAction);
+    }
+
     private class MainHandler extends Handler {
         private static final int PLUGIN_CONNECTED = 1;
         private static final int PLUGIN_DISCONNECTED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
index 03747d5..2a17e35 100644
--- a/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/plugins/PluginManagerImpl.java
@@ -50,6 +50,8 @@
 
 import dalvik.system.PathClassLoader;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.lang.Thread.UncaughtExceptionHandler;
 import java.util.Map;
 
@@ -303,6 +305,14 @@
         }
     }
 
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println(String.format("  plugin map (%d):", mPluginMap.size()));
+        for (PluginListener listener: mPluginMap.keySet()) {
+            pw.println(String.format("    %s -> %s",
+                    listener, mPluginMap.get(listener)));
+        }
+    }
+
     @VisibleForTesting
     public static class PluginInstanceManagerFactory {
         public <T extends Plugin> PluginInstanceManager createPluginInstanceManager(Context context,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index fccd9ce..222c6e82 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -44,7 +44,6 @@
 
     public static final float EXPANDED_TILE_DELAY = .86f;
 
-
     private final ArrayList<View> mAllViews = new ArrayList<>();
     /**
      * List of {@link View}s representing Quick Settings that are being animated from the quick QS
@@ -66,11 +65,6 @@
     private TouchAnimator mNonfirstPageDelayedAnimator;
     private TouchAnimator mBrightnessAnimator;
 
-    /**
-     * Whether the animation is stable and not in the middle of animating between the collapsed and
-     * expanded states.
-     */
-    private boolean mIsInStableState;
     private boolean mOnKeyguard;
 
     private boolean mAllowFancy;
@@ -95,10 +89,6 @@
             Log.w(TAG, "QS Not using page layout");
         }
         panel.setPageListener(this);
-
-        // At time of creation, the QS panel is always considered stable as it's not in the middle
-        // of collapse/expanded.
-        mIsInStableState = true;
     }
 
     public void onRtlChanged() {
@@ -253,11 +243,6 @@
             } else {
                 mBrightnessAnimator = null;
             }
-            View headerView = mQsPanel.getHeaderView();
-            if (headerView!= null) {
-                firstPageBuilder.addFloat(headerView, "translationY", heightDiff, 0);
-                mAllViews.add(headerView);
-            }
             mFirstPageAnimator = firstPageBuilder
                     .setListener(this)
                     .build();
@@ -341,21 +326,11 @@
 
     @Override
     public void onAnimationAtStart() {
-        if (!mIsInStableState) {
-            mQsPanel.onCollapse();
-        }
-        mIsInStableState = true;
-
         mQuickQsPanel.setVisibility(View.VISIBLE);
     }
 
     @Override
     public void onAnimationAtEnd() {
-        if (!mIsInStableState) {
-            mQsPanel.onExpanded();
-        }
-        mIsInStableState = true;
-
         mQuickQsPanel.setVisibility(View.INVISIBLE);
         final int N = mQuickQsViews.size();
         for (int i = 0; i < N; i++) {
@@ -365,11 +340,6 @@
 
     @Override
     public void onAnimationStarted() {
-        if (mIsInStableState) {
-            mQsPanel.onAnimating();
-        }
-        mIsInStableState = false;
-
         mQuickQsPanel.setVisibility(mOnKeyguard ? View.INVISIBLE : View.VISIBLE);
         if (mOnFirstPage) {
             final int N = mQuickQsViews.size();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 5640be5..f7c388d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.qs.tileimpl.QSTileImpl.getColorForState;
 
-import android.annotation.Nullable;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -59,7 +58,6 @@
 public class QSPanel extends LinearLayout implements Tunable, Callback, BrightnessMirrorListener {
 
     public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
-    public static final String QS_SHOW_LONG_PRESS_TOOLTIP = "qs_show_long_press";
 
     protected final Context mContext;
     protected final ArrayList<TileRecord> mRecords = new ArrayList<TileRecord>();
@@ -74,7 +72,6 @@
     private BrightnessController mBrightnessController;
     protected QSTileHost mHost;
 
-    protected QSTooltipView mTooltipView;
     protected QSSecurityFooter mFooter;
     private boolean mGridContentVisible = true;
 
@@ -97,9 +94,6 @@
 
         setOrientation(VERTICAL);
 
-        mTooltipView = (QSTooltipView) LayoutInflater.from(mContext)
-                .inflate(R.layout.quick_settings_header, this, false);
-
         mBrightnessView = LayoutInflater.from(mContext).inflate(
             R.layout.quick_settings_brightness_dialog, this, false);
         mTileLayout = new TileLayout(mContext);
@@ -107,12 +101,7 @@
         Space space = new Space(mContext);
         space.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
                 mContext.getResources().getDimensionPixelSize(R.dimen.qs_footer_height)));
-        mScrollLayout = new QSScrollLayout(
-                mContext,
-                mTooltipView,
-                mBrightnessView,
-                (View) mTileLayout,
-                space);
+        mScrollLayout = new QSScrollLayout(mContext, mBrightnessView, (View) mTileLayout, space);
         addView(mScrollLayout);
 
         addDivider();
@@ -145,10 +134,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        final TunerService tunerService = Dependency.get(TunerService.class);
-        tunerService.addTunable(this, QS_SHOW_BRIGHTNESS);
-        tunerService.addTunable(this, QS_SHOW_LONG_PRESS_TOOLTIP);
-
+        Dependency.get(TunerService.class).addTunable(this, QS_SHOW_BRIGHTNESS);
         if (mHost != null) {
             setTiles(mHost.getTiles());
         }
@@ -180,16 +166,11 @@
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (QS_SHOW_BRIGHTNESS.equals(key)) {
-            updateViewVisibilityForTuningValue(mBrightnessView, newValue);
-        } else if (QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
-            updateViewVisibilityForTuningValue(mTooltipView, newValue);
+            mBrightnessView.setVisibility(newValue == null || Integer.parseInt(newValue) != 0
+                    ? VISIBLE : GONE);
         }
     }
 
-    private void updateViewVisibilityForTuningValue(View view, @Nullable String newValue) {
-        view.setVisibility(newValue == null || Integer.parseInt(newValue) != 0 ? VISIBLE : GONE);
-    }
-
     public void openDetails(String subPanel) {
         QSTile tile = getTile(subPanel);
         showDetailAdapter(true, tile.getDetailAdapter(), new int[]{getWidth() / 2, 0});
@@ -224,10 +205,6 @@
         return mBrightnessView;
     }
 
-    View getHeaderView() {
-        return mTooltipView;
-    }
-
     public void setCallback(QSDetail.Callback callback) {
         mCallback = callback;
     }
@@ -289,27 +266,11 @@
         if (mCustomizePanel != null && mCustomizePanel.isShown()) {
             mCustomizePanel.hide(mCustomizePanel.getWidth() / 2, mCustomizePanel.getHeight() / 2);
         }
-
-        // Instantly hide the header here since we don't want it to still be animating.
-        mTooltipView.setVisibility(View.INVISIBLE);
-    }
-
-    /**
-     * Called when the panel is fully animated out/expanded. This is different from the state
-     * tracked by {@link #mExpanded}, which only checks if the panel is even partially pulled out.
-     */
-    public void onExpanded() {
-        mTooltipView.fadeIn();
-    }
-
-    public void onAnimating() {
-        mTooltipView.fadeOut();
     }
 
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
-
         if (!mExpanded) {
             if (mTileLayout instanceof PagedTileLayout) {
                 ((PagedTileLayout) mTileLayout).setCurrentItem(0, false);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
deleted file mode 100644
index d1f9741..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTooltipView.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2018 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.systemui.qs;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.content.Context;
-import android.os.Handler;
-import android.util.AttributeSet;
-import android.view.View;
-import android.widget.LinearLayout;
-
-import com.android.systemui.Prefs;
-
-import java.util.concurrent.TimeUnit;
-
-
-/**
- * Tooltip/header view for the Quick Settings panel.
- */
-public class QSTooltipView extends LinearLayout {
-
-    private static final int FADE_ANIMATION_DURATION_MS = 300;
-    private static final long AUTO_FADE_OUT_DELAY_MS = TimeUnit.SECONDS.toMillis(6);
-    private static final int TOOLTIP_NOT_YET_SHOWN_COUNT = 0;
-    public static final int MAX_TOOLTIP_SHOWN_COUNT = 3;
-
-    private final Handler mHandler = new Handler();
-    private final Runnable mAutoFadeOutRunnable = () -> fadeOut();
-
-    private int mShownCount;
-
-    public QSTooltipView(Context context) {
-        this(context, null);
-    }
-
-    public QSTooltipView(Context context, AttributeSet attrs) {
-        super(context, attrs);
-        mShownCount = getStoredShownCount();
-    }
-
-    /** Returns the latest stored tooltip shown count from SharedPreferences. */
-    private int getStoredShownCount() {
-        return Prefs.getInt(
-                mContext,
-                Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
-                TOOLTIP_NOT_YET_SHOWN_COUNT);
-    }
-
-    /**
-     * Fades in the header view if we can show the tooltip - short circuits any running animation.
-     */
-    public void fadeIn() {
-        if (mShownCount < MAX_TOOLTIP_SHOWN_COUNT) {
-            animate().cancel();
-            setVisibility(View.VISIBLE);
-            animate()
-                    .alpha(1f)
-                    .setDuration(FADE_ANIMATION_DURATION_MS)
-                    .setListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            mHandler.postDelayed(mAutoFadeOutRunnable, AUTO_FADE_OUT_DELAY_MS);
-                        }
-                    })
-                    .start();
-
-            // Increment and drop the shown count in prefs for the next time we're deciding to
-            // fade in the tooltip. We first sanity check that the tooltip count hasn't changed yet
-            // in prefs (say, from a long press).
-            if (getStoredShownCount() <= mShownCount) {
-                Prefs.putInt(mContext, Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT, ++mShownCount);
-            }
-        }
-    }
-
-    /**
-     * Fades out the header view if it's partially visible - short circuits any running animation.
-     */
-    public void fadeOut() {
-        animate().cancel();
-        if (getVisibility() == View.VISIBLE && getAlpha() != 0f) {
-            mHandler.removeCallbacks(mAutoFadeOutRunnable);
-            animate()
-                    .alpha(0f)
-                    .setDuration(FADE_ANIMATION_DURATION_MS)
-                    .setListener(new AnimatorListenerAdapter() {
-                        @Override
-                        public void onAnimationEnd(Animator animation) {
-                            perhapsMakeViewInvisible();
-                        }
-                    })
-                    .start();
-        } else {
-            perhapsMakeViewInvisible();
-        }
-    }
-
-    /**
-     * Only update visibility if the view is currently being shown. Otherwise, it's already been
-     * hidden by some other manner.
-     */
-    private void perhapsMakeViewInvisible() {
-        if (getVisibility() == View.VISIBLE) {
-            setVisibility(View.INVISIBLE);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
index 1b4b7df..8314855 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
@@ -124,8 +124,9 @@
 
     @Override
     public void onTuningChanged(String key, String newValue) {
-        if (QS_SHOW_BRIGHTNESS.equals(key) || QS_SHOW_LONG_PRESS_TOOLTIP.equals(key)) {
-            // No Brightness or Tooltip for you!
+        // No tunings for you.
+        if (key.equals(QS_SHOW_BRIGHTNESS)) {
+            // No Brightness for you.
             super.onTuningChanged(key, "0");
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
index 9fa7beb..65135ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java
@@ -99,11 +99,7 @@
             record.tileView.measure(exactly(mCellWidth), exactly(mCellHeight));
             previousView = record.tileView.updateAccessibilityOrder(previousView);
         }
-
-        // Only include the top margin in our measurement if we have more than 1 row to show.
-        // Otherwise, don't add the extra margin buffer at top.
-        int height = (mCellHeight + mCellMargin) * rows +
-                rows != 0 ? (mCellMarginTop - mCellMargin) : 0;
+        int height = (mCellHeight + mCellMargin) * rows + (mCellMarginTop - mCellMargin);
         if (height < 0) height = 0;
         setMeasuredDimension(width, height);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
index 6263efa..37f2528 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java
@@ -107,7 +107,7 @@
         void onAnimationAtStart();
 
         /**
-         * Called when the animator moves into a position of "1". Start and end delays are
+         * Called when the animator moves into a position of "0". Start and end delays are
          * taken into account, so this position may cover a range of fractional inputs.
          */
         void onAnimationAtEnd();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 016cbd6..72592829 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -42,7 +42,6 @@
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
-import com.android.systemui.Prefs;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.qs.DetailAdapter;
 import com.android.systemui.plugins.qs.QSIconView;
@@ -50,7 +49,6 @@
 import com.android.systemui.plugins.qs.QSTile.State;
 import com.android.systemui.qs.PagedTileLayout.TilePage;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.qs.QSTooltipView;
 
 import java.util.ArrayList;
 
@@ -193,11 +191,6 @@
     public void longClick() {
         mMetricsLogger.write(populate(new LogMaker(ACTION_QS_LONG_PRESS).setType(TYPE_ACTION)));
         mHandler.sendEmptyMessage(H.LONG_CLICK);
-
-        Prefs.putInt(
-                mContext,
-                Prefs.Key.QS_LONG_PRESS_TOOLTIP_SHOWN_COUNT,
-                QSTooltipView.MAX_TOOLTIP_SHOWN_COUNT);
     }
 
     public LogMaker populate(LogMaker logMaker) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 7fe9e35..2a9a381 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -78,6 +78,7 @@
 
     @Override
     public void handleSetListening(boolean listening) {
+        if (mController == null) return;
         if (listening) {
             mController.addCallback(mCallback);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 6205e9a..2d31669 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -240,6 +240,7 @@
     public void handleSetListening(boolean listening) {
         if (mListening == listening) return;
         mListening = listening;
+        if (mController == null) return;
         if (mListening) {
             mController.addCallback(mZenCallback);
             Prefs.registerListener(mContext, mPrefListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
index b3ff4e5b..12daff1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -98,6 +98,8 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
         final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
+
+        if (getAdapter() == null) return;
         state.value = getAdapter().isEnabled();
         state.label = mContext.getString(R.string.quick_settings_nfc_label);
         state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index b7a1500..22e8909 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -300,34 +300,10 @@
                 } else if (mPowerPluggedIn) {
                     String indication = computePowerIndication();
                     if (animate) {
-                        int yTranslation = mContext.getResources().getInteger(
-                                R.integer.wired_charging_aod_text_animation_distance);
-                        int animateUpDuration = mContext.getResources().getInteger(
-                                R.integer.wired_charging_aod_text_animation_duration_up);
-                        int animateDownDuration = mContext.getResources().getInteger(
-                                R.integer.wired_charging_aod_text_animation_duration_down);
-                        mTextView.animate()
-                                .translationYBy(yTranslation)
-                                .setInterpolator(Interpolators.LINEAR)
-                                .setDuration(animateUpDuration)
-                                .setListener(new AnimatorListenerAdapter() {
-                                    @Override
-                                    public void onAnimationStart(Animator animation) {
-                                        mTextView.switchIndication(indication);
-                                    }
-                                    @Override
-                                    public void onAnimationEnd(Animator animation) {
-                                        mTextView.animate()
-                                                .setDuration(animateDownDuration)
-                                                .setInterpolator(Interpolators.BOUNCE)
-                                                .translationYBy(-1 * yTranslation)
-                                                .setListener(null);
-                                    }
-                                });
+                        animateText(mTextView, indication);
                     } else {
                         mTextView.switchIndication(indication);
                     }
-
                 } else {
                     String percentage = NumberFormat.getPercentInstance()
                             .format(mBatteryLevel / 100f);
@@ -355,8 +331,12 @@
                 if (DEBUG_CHARGING_SPEED) {
                     indication += ",  " + (mChargingWattage / 1000) + " mW";
                 }
-                mTextView.switchIndication(indication);
                 mTextView.setTextColor(mInitialTextColor);
+                if (animate) {
+                    animateText(mTextView, indication);
+                } else {
+                    mTextView.switchIndication(indication);
+                }
             } else if (!TextUtils.isEmpty(trustManagedIndication)
                     && updateMonitor.getUserTrustIsManaged(userId)
                     && !updateMonitor.getUserHasTrust(userId)) {
@@ -369,6 +349,34 @@
         }
     }
 
+    // animates textView - textView moves up and bounces down
+    private void animateText(KeyguardIndicationTextView textView, String indication) {
+        int yTranslation = mContext.getResources().getInteger(
+                R.integer.wired_charging_keyguard_text_animation_distance);
+        int animateUpDuration = mContext.getResources().getInteger(
+                R.integer.wired_charging_keyguard_text_animation_duration_up);
+        int animateDownDuration = mContext.getResources().getInteger(
+                R.integer.wired_charging_keyguard_text_animation_duration_down);
+        textView.animate()
+                .translationYBy(yTranslation)
+                .setInterpolator(Interpolators.LINEAR)
+                .setDuration(animateUpDuration)
+                .setListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationStart(Animator animation) {
+                        textView.switchIndication(indication);
+                    }
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        textView.animate()
+                                .setDuration(animateDownDuration)
+                                .setInterpolator(Interpolators.BOUNCE)
+                                .translationYBy(-1 * yTranslation)
+                                .setListener(null);
+                    }
+                });
+    }
+
     private String computePowerIndication() {
         if (mPowerCharged) {
             return mContext.getResources().getString(R.string.keyguard_charged);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 0dea6b8..c047670 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -403,14 +403,18 @@
     }
 
     private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
+        final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled();
         if (oldConfig.orientation != newConfig.orientation
                 || oldConfig.densityDpi != newConfig.densityDpi) {
             mDockedIcon = getDrawable(ctx,
                     R.drawable.ic_sysbar_docked, R.drawable.ic_sysbar_docked_dark);
+            mHomeDefaultIcon = quickStepEnabled
+                    ? getDrawable(ctx, R.drawable.ic_sysbar_home_quick_step,
+                    R.drawable.ic_sysbar_home_quick_step_dark)
+                    : getDrawable(ctx, R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
         }
         if (oldConfig.densityDpi != newConfig.densityDpi
                 || oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
-            final boolean quickStepEnabled = isQuickStepSwipeUpEnabled() || isQuickScrubEnabled();
             mBackIcon = quickStepEnabled
                     ? getDrawable(ctx, R.drawable.ic_sysbar_back_quick_step,
                             R.drawable.ic_sysbar_back_quick_step_dark)
@@ -422,11 +426,6 @@
                     : getDrawable(ctx, R.drawable.ic_sysbar_back_ime,
                             R.drawable.ic_sysbar_back_ime_dark);
             mBackAltLandIcon = mBackAltIcon;
-
-            mHomeDefaultIcon = quickStepEnabled
-                    ? getDrawable(ctx, R.drawable.ic_sysbar_home_quick_step,
-                            R.drawable.ic_sysbar_home_quick_step_dark)
-                    : getDrawable(ctx, R.drawable.ic_sysbar_home, R.drawable.ic_sysbar_home_dark);
             mRecentIcon = getDrawable(ctx,
                     R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
             mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
index 0bf01b0..378858a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
@@ -224,6 +224,10 @@
             case MotionEvent.ACTION_DOWN: {
                 int x = (int) event.getX();
                 int y = (int) event.getY();
+                // End any existing quickscrub animations before starting the new transition
+                if (mQuickScrubEndAnimator != null) {
+                    mQuickScrubEndAnimator.end();
+                }
                 mHomeButtonView = homeButton.getCurrentView();
                 if (mNavigationBarView.isQuickScrubEnabled()
                         && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index 6764634..1c9c794 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -37,7 +37,6 @@
 import android.content.Intent;
 import android.metrics.LogMaker;
 import android.support.test.filters.SmallTest;
-import android.support.test.InstrumentationRegistry;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -74,7 +73,6 @@
         mMetricsLogger = mDependency.injectMockDependency(MetricsLogger.class);
         mHost = mock(QSTileHost.class);
         when(mHost.indexOf(spec)).thenReturn(POSITION);
-        when(mHost.getContext()).thenReturn(mContext.getBaseContext());
 
         mTile = spy(new TileImpl(mHost));
         mTile.mHandler = mTile.new H(mTestableLooper.getLooper());
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 320c37f..abf1de5 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5257,6 +5257,23 @@
     // OS: P
     FIELD_END_BATTERY_PERCENT = 1308;
 
+    // ACTION: Settings > Display > Night Light
+    // SUBTYPE: com.android.server.display.ColorDisplayService.AutoMode value
+    // CATEGORY: SETTINGS
+    // OS: P
+    ACTION_NIGHT_DISPLAY_AUTO_MODE_CHANGED = 1309;
+
+    // ACTION: Settings > Display > Night Light
+    // CATEGORY: SETTINGS
+    // SUBTYPE: 0 is starting time, 1 is ending time
+    // OS: P
+    ACTION_NIGHT_DISPLAY_AUTO_MODE_CUSTOM_TIME_CHANGED = 1310;
+
+    // FIELD: Current mode corresponding to a QS tile
+    // CATEGORY: QUICK SETTINGS
+    // OS: P
+    FIELD_QS_MODE = 1311;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/rs/OWNERS b/rs/OWNERS
new file mode 100644
index 0000000..61853d3
--- /dev/null
+++ b/rs/OWNERS
@@ -0,0 +1,5 @@
+butlermichael@google.com
+dgross@google.com
+jeanluc@google.com
+miaowang@google.com
+yangni@google.com
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 4b3abea..3689536 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -514,7 +514,7 @@
      */
     @GuardedBy("mLock")
     private void updateCachedServiceLocked(int userId, boolean disabled) {
-        AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+        AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
         if (service != null) {
             service.destroySessionsLocked();
             service.updateLocked(disabled);
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index c023efb..c504465 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -153,8 +153,8 @@
                 mWindow = null;
                 return;
             }
-            content.setFocusable(true);
-            content.setOnClickListener(v -> mCallback.onResponsePicked(response));
+            decor.setFocusable(true);
+            decor.setOnClickListener(v -> mCallback.onResponsePicked(response));
 
             Point maxSize = mTempPoint;
             resolveMaxWindowSize(context, maxSize);
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 1a0068d..7c109d5 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -16,6 +16,15 @@
 
 package com.android.server;
 
+import static android.os.storage.OnObbStateChangeListener.ERROR_ALREADY_MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT;
+import static android.os.storage.OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT;
+import static android.os.storage.OnObbStateChangeListener.ERROR_INTERNAL;
+import static android.os.storage.OnObbStateChangeListener.ERROR_NOT_MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.ERROR_PERMISSION_DENIED;
+import static android.os.storage.OnObbStateChangeListener.MOUNTED;
+import static android.os.storage.OnObbStateChangeListener.UNMOUNTED;
+
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
 import static com.android.internal.util.XmlUtils.readIntAttribute;
 import static com.android.internal.util.XmlUtils.readLongAttribute;
@@ -60,7 +69,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.IProgressListener;
 import android.os.IStoraged;
 import android.os.IVold;
 import android.os.IVoldListener;
@@ -87,7 +95,6 @@
 import android.os.storage.OnObbStateChangeListener;
 import android.os.storage.StorageManager;
 import android.os.storage.StorageManagerInternal;
-import android.os.storage.StorageResultCode;
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
@@ -137,8 +144,7 @@
 import java.io.PrintWriter;
 import java.math.BigInteger;
 import java.nio.charset.StandardCharsets;
-import java.security.NoSuchAlgorithmException;
-import java.security.spec.InvalidKeySpecException;
+import java.security.GeneralSecurityException;
 import java.security.spec.KeySpec;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -3032,8 +3038,8 @@
                         // If this is the only one pending we might
                         // have to bind to the service again.
                         if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
-                            action.handleError();
+                            action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+                                    "Failed to bind to media container service"));
                             return;
                         }
                     }
@@ -3049,10 +3055,10 @@
                     }
                     if (mContainerService == null) {
                         // Something seriously wrong. Bail out
-                        Slog.e(TAG, "Cannot bind to media container service");
                         for (ObbAction action : mActions) {
                             // Indicate service bind error
-                            action.handleError();
+                            action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+                                    "Failed to bind to media container service"));
                         }
                         mActions.clear();
                     } else if (mActions.size() > 0) {
@@ -3074,10 +3080,10 @@
                             disconnectService();
                         }
                         if (!connectToService()) {
-                            Slog.e(TAG, "Failed to bind to media container service");
                             for (ObbAction action : mActions) {
                                 // Indicate service bind error
-                                action.handleError();
+                                action.notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+                                        "Failed to bind to media container service"));
                             }
                             mActions.clear();
                         }
@@ -3167,6 +3173,20 @@
         }
     }
 
+    private static class ObbException extends Exception {
+        public final int status;
+
+        public ObbException(int status, String message) {
+            super(message);
+            this.status = status;
+        }
+
+        public ObbException(int status, Throwable cause) {
+            super(cause.getMessage(), cause);
+            this.status = status;
+        }
+    }
+
     abstract class ObbAction {
         private static final int MAX_RETRIES = 3;
         private int mRetries;
@@ -3183,46 +3203,44 @@
                     Slog.i(TAG, "Starting to execute action: " + toString());
                 mRetries++;
                 if (mRetries > MAX_RETRIES) {
-                    Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");
                     mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
-                    handleError();
+                    notifyObbStateChange(new ObbException(ERROR_INTERNAL,
+                            "Failed to bind to media container service"));
                 } else {
                     handleExecute();
                     if (DEBUG_OBB)
                         Slog.i(TAG, "Posting install MCS_UNBIND");
                     mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
                 }
-            } catch (RemoteException e) {
-                if (DEBUG_OBB)
-                    Slog.i(TAG, "Posting install MCS_RECONNECT");
-                mObbActionHandler.sendEmptyMessage(OBB_MCS_RECONNECT);
-            } catch (Exception e) {
-                if (DEBUG_OBB)
-                    Slog.d(TAG, "Error handling OBB action", e);
-                handleError();
+            } catch (ObbException e) {
+                notifyObbStateChange(e);
                 mObbActionHandler.sendEmptyMessage(OBB_MCS_UNBIND);
             }
         }
 
-        abstract void handleExecute() throws RemoteException, IOException;
-        abstract void handleError();
+        abstract void handleExecute() throws ObbException;
 
-        protected ObbInfo getObbInfo() throws IOException {
-            ObbInfo obbInfo;
+        protected ObbInfo getObbInfo() throws ObbException {
+            final ObbInfo obbInfo;
             try {
                 obbInfo = mContainerService.getObbInfo(mObbState.canonicalPath);
-            } catch (RemoteException e) {
-                Slog.d(TAG, "Couldn't call DefaultContainerService to fetch OBB info for "
-                        + mObbState.canonicalPath);
-                obbInfo = null;
+            } catch (Exception e) {
+                throw new ObbException(ERROR_PERMISSION_DENIED, e);
             }
-            if (obbInfo == null) {
-                throw new IOException("Couldn't read OBB file: " + mObbState.canonicalPath);
+            if (obbInfo != null) {
+                return obbInfo;
+            } else {
+                throw new ObbException(ERROR_INTERNAL,
+                        "Missing OBB info for: " + mObbState.canonicalPath);
             }
-            return obbInfo;
         }
 
-        protected void sendNewStatusOrIgnore(int status) {
+        protected void notifyObbStateChange(ObbException e) {
+            Slog.w(TAG, e);
+            notifyObbStateChange(e.status);
+        }
+
+        protected void notifyObbStateChange(int status) {
             if (mObbState == null || mObbState.token == null) {
                 return;
             }
@@ -3246,16 +3264,14 @@
         }
 
         @Override
-        public void handleExecute() throws IOException, RemoteException {
+        public void handleExecute() throws ObbException {
             warnOnNotMounted();
 
             final ObbInfo obbInfo = getObbInfo();
 
             if (!isUidOwnerOfPackageOrSystem(obbInfo.packageName, mCallingUid)) {
-                Slog.w(TAG, "Denied attempt to mount OBB " + obbInfo.filename
-                        + " which is owned by " + obbInfo.packageName);
-                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
-                return;
+                throw new ObbException(ERROR_PERMISSION_DENIED, "Denied attempt to mount OBB "
+                        + obbInfo.filename + " which is owned by " + obbInfo.packageName);
             }
 
             final boolean isMounted;
@@ -3263,9 +3279,8 @@
                 isMounted = mObbPathToStateMap.containsKey(mObbState.rawPath);
             }
             if (isMounted) {
-                Slog.w(TAG, "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
-                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_ALREADY_MOUNTED);
-                return;
+                throw new ObbException(ERROR_ALREADY_MOUNTED,
+                        "Attempt to mount OBB which is already mounted: " + obbInfo.filename);
             }
 
             final String hashedKey;
@@ -3283,28 +3298,16 @@
                     BigInteger bi = new BigInteger(key.getEncoded());
                     hashedKey = bi.toString(16);
                     binderKey = hashedKey;
-                } catch (NoSuchAlgorithmException e) {
-                    Slog.e(TAG, "Could not load PBKDF2 algorithm", e);
-                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
-                    return;
-                } catch (InvalidKeySpecException e) {
-                    Slog.e(TAG, "Invalid key spec when loading PBKDF2 algorithm", e);
-                    sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
-                    return;
+                } catch (GeneralSecurityException e) {
+                    throw new ObbException(ERROR_INTERNAL, e);
                 }
             }
 
-            int rc = StorageResultCode.OperationSucceeded;
             try {
                 mObbState.volId = mVold.createObb(mObbState.canonicalPath, binderKey,
                         mObbState.ownerGid);
                 mVold.mount(mObbState.volId, 0, -1);
-            } catch (Exception e) {
-                Slog.w(TAG, e);
-                rc = StorageResultCode.OperationFailedInternalError;
-            }
 
-            if (rc == StorageResultCode.OperationSucceeded) {
                 if (DEBUG_OBB)
                     Slog.d(TAG, "Successfully mounted OBB " + mObbState.canonicalPath);
 
@@ -3312,20 +3315,13 @@
                     addObbStateLocked(mObbState);
                 }
 
-                sendNewStatusOrIgnore(OnObbStateChangeListener.MOUNTED);
-            } else {
-                Slog.e(TAG, "Couldn't mount OBB file: " + rc);
-
-                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_MOUNT);
+                notifyObbStateChange(MOUNTED);
+            } catch (Exception e) {
+                throw new ObbException(ERROR_COULD_NOT_MOUNT, e);
             }
         }
 
         @Override
-        public void handleError() {
-            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
-        }
-
-        @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
             sb.append("MountObbAction{");
@@ -3344,7 +3340,7 @@
         }
 
         @Override
-        public void handleExecute() throws IOException {
+        public void handleExecute() throws ObbException {
             warnOnNotMounted();
 
             final ObbState existingState;
@@ -3353,45 +3349,32 @@
             }
 
             if (existingState == null) {
-                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_NOT_MOUNTED);
-                return;
+                throw new ObbException(ERROR_NOT_MOUNTED, "Missing existingState");
             }
 
             if (existingState.ownerGid != mObbState.ownerGid) {
-                Slog.w(TAG, "Permission denied attempting to unmount OBB " + existingState.rawPath
-                        + " (owned by GID " + existingState.ownerGid + ")");
-                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_PERMISSION_DENIED);
+                notifyObbStateChange(new ObbException(ERROR_PERMISSION_DENIED,
+                        "Permission denied to unmount OBB " + existingState.rawPath
+                                + " (owned by GID " + existingState.ownerGid + ")"));
                 return;
             }
 
-            int rc = StorageResultCode.OperationSucceeded;
             try {
                 mVold.unmount(mObbState.volId);
                 mVold.destroyObb(mObbState.volId);
                 mObbState.volId = null;
-            } catch (Exception e) {
-                Slog.w(TAG, e);
-                rc = StorageResultCode.OperationFailedInternalError;
-            }
 
-            if (rc == StorageResultCode.OperationSucceeded) {
                 synchronized (mObbMounts) {
                     removeObbStateLocked(existingState);
                 }
 
-                sendNewStatusOrIgnore(OnObbStateChangeListener.UNMOUNTED);
-            } else {
-                Slog.w(TAG, "Could not unmount OBB: " + existingState);
-                sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_COULD_NOT_UNMOUNT);
+                notifyObbStateChange(UNMOUNTED);
+            } catch (Exception e) {
+                throw new ObbException(ERROR_COULD_NOT_UNMOUNT, e);
             }
         }
 
         @Override
-        public void handleError() {
-            sendNewStatusOrIgnore(OnObbStateChangeListener.ERROR_INTERNAL);
-        }
-
-        @Override
         public String toString() {
             StringBuilder sb = new StringBuilder();
             sb.append("UnmountObbAction{");
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5c30764..f4f60c2 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -4516,7 +4516,7 @@
 
     int startActivityFromRecents(int callingPid, int callingUid, int taskId,
             SafeActivityOptions options) {
-        final TaskRecord task;
+        TaskRecord task = null;
         final String callingPackage;
         final Intent intent;
         final int userId;
@@ -4579,13 +4579,6 @@
                             targetActivity);
                 }
 
-                // If we are launching the task in the docked stack, put it into resizing mode so
-                // the window renders full-screen with the background filling the void. Also only
-                // call this at the end to make sure that tasks exists on the window manager side.
-                if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                    setResizingDuringAnimation(task);
-                }
-
                 mService.getActivityStartController().postStartActivityProcessingForLastStarter(
                         task.getTopActivity(), ActivityManager.START_TASK_TO_FRONT,
                         task.getStack());
@@ -4595,15 +4588,28 @@
             intent = task.intent;
             intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
             userId = task.userId;
-            int result = mService.getActivityStartController().startActivityInPackage(
+            return mService.getActivityStartController().startActivityInPackage(
                     task.mCallingUid, callingPid, callingUid, callingPackage, intent, null, null,
-                    null, 0, 0, options, userId, task,
-                    "startActivityFromRecents");
-            if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
-                setResizingDuringAnimation(task);
-            }
-            return result;
+                    null, 0, 0, options, userId, task, "startActivityFromRecents");
         } finally {
+            if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY && task != null) {
+                // If we are launching the task in the docked stack, put it into resizing mode so
+                // the window renders full-screen with the background filling the void. Also only
+                // call this at the end to make sure that tasks exists on the window manager side.
+                setResizingDuringAnimation(task);
+
+                final ActivityDisplay display = task.getStack().getDisplay();
+                final ActivityStack topSecondaryStack =
+                        display.getTopStackInWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+                if (topSecondaryStack.isActivityTypeHome()) {
+                    // If the home activity if the top split-screen secondary stack, then the
+                    // primary split-screen stack is in the minimized mode which means it can't
+                    // receive input keys, so we should move the focused app to the home app so that
+                    // window manager can correctly calculate the focus window that can receive
+                    // input keys.
+                    moveHomeStackToFront("startActivityFromRecents: homeVisibleInSplitScreen");
+                }
+            }
             mWindowManager.continueSurfaceLayout();
         }
     }
diff --git a/services/core/java/com/android/server/audio/OWNERS b/services/core/java/com/android/server/audio/OWNERS
new file mode 100644
index 0000000..b70de29
--- /dev/null
+++ b/services/core/java/com/android/server/audio/OWNERS
@@ -0,0 +1,2 @@
+jmtrivi@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index d87a1bb..79450a0 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -2078,8 +2078,33 @@
     protected void dumpSyncState(PrintWriter pw) {
         final StringBuilder sb = new StringBuilder();
 
-        pw.print("data connected: "); pw.println(mDataConnectionIsConnected);
-        pw.print("auto sync: ");
+        pw.print("Data connected: "); pw.println(mDataConnectionIsConnected);
+        pw.print("Battery saver: ");
+        pw.println((mPowerManager != null) && mPowerManager.isPowerSaveMode());
+
+        pw.print("Background network restriction: ");
+        {
+            final ConnectivityManager cm = getConnectivityManager();
+            final int status = (cm == null) ? -1 : cm.getRestrictBackgroundStatus();
+            switch (status) {
+                case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED:
+                    pw.println(" disabled");
+                    break;
+                case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_WHITELISTED:
+                    pw.println(" whitelisted");
+                    break;
+                case ConnectivityManager.RESTRICT_BACKGROUND_STATUS_ENABLED:
+                    pw.println(" enabled");
+                    break;
+                default:
+                    pw.print("Unknown(");
+                    pw.print(status);
+                    pw.println(")");
+                    break;
+            }
+        }
+
+        pw.print("Auto sync: ");
         List<UserInfo> users = getAllUsers();
         if (users != null) {
             for (UserInfo user : users) {
@@ -2088,26 +2113,26 @@
             }
             pw.println();
         }
-        pw.print("memory low: "); pw.println(mStorageIsLow);
-        pw.print("device idle: "); pw.println(mDeviceIsIdle);
-        pw.print("reported active: "); pw.println(mReportedSyncActive);
+        pw.print("Memory low: "); pw.println(mStorageIsLow);
+        pw.print("Device idle: "); pw.println(mDeviceIsIdle);
+        pw.print("Reported active: "); pw.println(mReportedSyncActive);
 
         final AccountAndUser[] accounts = AccountManagerService.getSingleton().getAllAccounts();
 
-        pw.print("accounts: ");
+        pw.print("Accounts: ");
         if (accounts != INITIAL_ACCOUNTS_ARRAY) {
             pw.println(accounts.length);
         } else {
             pw.println("not known yet");
         }
         final long now = SystemClock.elapsedRealtime();
-        pw.print("now: "); pw.print(now);
+        pw.print("Now: "); pw.print(now);
         pw.println(" (" + formatTime(System.currentTimeMillis()) + ")");
 
         sb.setLength(0);
-        pw.print("uptime: "); pw.print(formatDurationHMS(sb, now));
+        pw.print("Uptime: "); pw.print(formatDurationHMS(sb, now));
         pw.println();
-        pw.print("time spent syncing: ");
+        pw.print("Time spent syncing: ");
 
         sb.setLength(0);
         pw.print(formatDurationHMS(sb,
diff --git a/services/core/java/com/android/server/content/SyncManagerConstants.java b/services/core/java/com/android/server/content/SyncManagerConstants.java
index 3139d54..061e4ca 100644
--- a/services/core/java/com/android/server/content/SyncManagerConstants.java
+++ b/services/core/java/com/android/server/content/SyncManagerConstants.java
@@ -55,7 +55,6 @@
     protected SyncManagerConstants(Context context) {
         super(null);
         mContext = context;
-        refresh();
     }
 
     public void start() {
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 3da3551..692535c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -421,7 +421,7 @@
                 byteToken[i] = token.get(i);
             }
             // Send to Keystore
-            KeyStore.getInstance().addAuthToken(byteToken);
+            KeyStore.getInstance().addAuthToken(byteToken, mCurrentUserId);
         }
         if (client != null && client.onAuthenticated(fingerId, groupId)) {
             removeClient(client);
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
old mode 100644
new mode 100755
index e5f4282..0cba76b
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -660,7 +660,8 @@
     @ServiceThreadOnly
     void startQueuedActions() {
         assertRunOnServiceThread();
-        for (HdmiCecFeatureAction action : mActions) {
+        // Use copied action list in that start() may remove itself.
+        for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) {
             if (!action.started()) {
                 Slog.i(TAG, "Starting queued action:" + action);
                 action.start();
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
new file mode 100644
index 0000000..6f8d823
--- /dev/null
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -0,0 +1,2 @@
+lajos@google.com
+elaurent@google.com
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 884606d2..c47381a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -553,9 +553,9 @@
 
     public static final String PLATFORM_PACKAGE_NAME = "android";
 
-    static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
+    public static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer";
 
-    static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
+    public static final ComponentName DEFAULT_CONTAINER_COMPONENT = new ComponentName(
             DEFAULT_CONTAINER_PACKAGE,
             "com.android.defcontainer.DefaultContainerService");
 
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6308766..c5cfb8e 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -16,7 +16,7 @@
 
 package com.android.server.pm.permission;
 
-import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+import static android.os.Process.FIRST_APPLICATION_UID;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -28,15 +28,14 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
 import android.content.pm.PackageList;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
+import android.content.pm.PackageManagerInternal.PackagesProvider;
+import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
 import android.content.pm.PackageParser;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
-import android.content.pm.PackageManagerInternal.PackagesProvider;
-import android.content.pm.PackageManagerInternal.SyncAdapterPackagesProvider;
 import android.media.RingtoneManager;
 import android.net.Uri;
 import android.os.Binder;
@@ -52,15 +51,17 @@
 import android.provider.ContactsContract;
 import android.provider.MediaStore;
 import android.provider.Telephony.Sms.Intents;
-import android.telephony.TelephonyManager;
 import android.security.Credentials;
+import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.Slog;
 import android.util.Xml;
+
 import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
+import com.android.server.pm.PackageManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -71,14 +72,11 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import static android.os.Process.FIRST_APPLICATION_UID;
-
 /**
  * This class is the policy for granting runtime permissions to
  * platform components and default handlers in the system such
@@ -433,6 +431,13 @@
             grantRuntimePermissions(storagePackage, STORAGE_PERMISSIONS, true, userId);
         }
 
+        // Container service
+        PackageParser.Package containerPackage = getSystemPackage(
+                PackageManagerService.DEFAULT_CONTAINER_PACKAGE);
+        if (containerPackage != null) {
+            grantRuntimePermissions(containerPackage, STORAGE_PERMISSIONS, true, userId);
+        }
+
         // CertInstaller
         Intent certInstallerIntent = new Intent(Credentials.INSTALL_ACTION);
         PackageParser.Package certInstallerPackage = getDefaultSystemHandlerActivityPackage(
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index 941cd44..efcadad 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -19,6 +19,8 @@
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.security.IKeystoreService;
 import android.util.Slog;
 
 import com.android.internal.policy.IKeyguardService;
@@ -51,11 +53,16 @@
     private final LockPatternUtils mLockPatternUtils;
     private final StateCallback mCallback;
 
+    IKeystoreService mKeystoreService;
+
     public KeyguardStateMonitor(Context context, IKeyguardService service, StateCallback callback) {
         mLockPatternUtils = new LockPatternUtils(context);
         mCurrentUserId = ActivityManager.getCurrentUser();
         mCallback = callback;
 
+        mKeystoreService = IKeystoreService.Stub.asInterface(ServiceManager
+                .getService("android.security.keystore"));
+
         try {
             service.addStateMonitorCallback(this);
         } catch (RemoteException e) {
@@ -86,6 +93,12 @@
     @Override // Binder interface
     public void onShowingStateChanged(boolean showing) {
         mIsShowing = showing;
+
+        if (showing) try {
+            mKeystoreService.lock(mCurrentUserId); // as long as this doesn't recur...
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Error locking keystore", e);
+        }
     }
 
     @Override // Binder interface
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 3cd3e8b..db95634 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -53,7 +53,8 @@
 
     AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) {
         mAppToken = appToken;
-        mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, appToken.mService);
+        mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
+                appToken.mService.mAnimator::addAfterPrepareSurfacesRunnable, appToken.mService);
         mWidth = thumbnailHeader.getWidth();
         mHeight = thumbnailHeader.getHeight();
 
@@ -144,6 +145,11 @@
     }
 
     @Override
+    public void destroyAfterPendingTransaction(SurfaceControl surface) {
+        mAppToken.destroyAfterPendingTransaction(surface);
+    }
+
+    @Override
     public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) {
         t.setLayer(leash, Integer.MAX_VALUE);
     }
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index a180a3a..4394a99 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -55,6 +55,11 @@
         }
 
         @Override
+        public void destroyAfterPendingTransaction(SurfaceControl surface) {
+            mHost.destroyAfterPendingTransaction(surface);
+        }
+
+        @Override
         public SurfaceControl.Builder makeAnimationLeash() {
             return mHost.makeAnimationLeash();
         }
@@ -114,7 +119,7 @@
                 if (!mDimming) {
                     mDimLayer.destroy();
                 }
-            }, mHost.mService);
+            }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2d32c81..d22828d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -380,6 +380,11 @@
      */
     private int mSurfaceSize;
 
+    /**
+     * A list of surfaces to be destroyed after {@link #mPendingTransaction} is applied.
+     */
+    private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
+
     /** Temporary float array to retrieve 3x3 matrix values. */
     private final float[] mTmpFloats = new float[9];
 
@@ -1930,6 +1935,10 @@
                 }
             }
             mService.mAnimator.removeDisplayLocked(mDisplayId);
+
+            // The pending transaction won't be applied so we should
+            // just clean up any surfaces pending destruction.
+            onPendingTransactionApplied();
         } finally {
             mRemovingDisplay = false;
         }
@@ -3846,6 +3855,22 @@
     }
 
     @Override
+    public void destroyAfterPendingTransaction(SurfaceControl surface) {
+        mPendingDestroyingSurfaces.add(surface);
+    }
+
+    /**
+     * Destroys any surfaces that have been put into the pending list with
+     * {@link #destroyAfterPendingTransaction}.
+     */
+    void onPendingTransactionApplied() {
+        for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
+            mPendingDestroyingSurfaces.get(i).destroy();
+        }
+        mPendingDestroyingSurfaces.clear();
+    }
+
+    @Override
     void prepareSurfaces() {
         final ScreenRotationAnimation screenRotationAnimation =
                 mService.mAnimator.getScreenRotationAnimationLocked(mDisplayId);
@@ -3859,7 +3884,6 @@
             mPendingTransaction.setAlpha(mWindowingLayer,
                     screenRotationAnimation.getEnterTransformation().getAlpha());
         }
-
         super.prepareSurfaces();
     }
 
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index e4edeb87..78dd580 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -219,7 +219,7 @@
     private void addAnimation(Task task) {
         if (DEBUG) Log.d(TAG, "addAnimation(" + task.getName() + ")");
         final SurfaceAnimator anim = new SurfaceAnimator(task, null /* animationFinishedCallback */,
-                mService);
+                mService.mAnimator::addAfterPrepareSurfacesRunnable, mService);
         final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task);
         anim.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
         task.commitPendingTransaction();
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 2fe55b9..3d60ee4 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -800,6 +800,7 @@
         mService.enableScreenIfNeededLocked();
 
         mService.scheduleAnimationLocked();
+        mService.mWindowPlacerLocked.destroyPendingSurfaces();
 
         if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
                 "performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 37be149..83baee1 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,6 +33,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.util.function.Consumer;
 
 /**
  * A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -59,17 +60,21 @@
     /**
      * @param animatable The object to animate.
      * @param animationFinishedCallback Callback to invoke when an animation has finished running.
+     * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
+     *                                surfaces in WM. Can be implemented differently during testing.
      */
     SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
-            WindowManagerService service) {
+            Consumer<Runnable> addAfterPrepareSurfaces, WindowManagerService service) {
         mAnimatable = animatable;
         mService = service;
         mAnimationFinishedCallback = animationFinishedCallback;
-        mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
+        mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback,
+                addAfterPrepareSurfaces);
     }
 
     private OnAnimationFinishedCallback getFinishedCallback(
-            @Nullable Runnable animationFinishedCallback) {
+            @Nullable Runnable animationFinishedCallback,
+            Consumer<Runnable> addAfterPrepareSurfaces) {
         return anim -> {
             synchronized (mService.mWindowMap) {
                 final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
@@ -78,13 +83,30 @@
                     return;
                 }
 
-                if (anim != mAnimation) {
-                    return;
-                }
-                reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
-                if (animationFinishedCallback != null) {
-                    animationFinishedCallback.run();
-                }
+                // TODO: This should use pendingTransaction eventually, but right now things
+                // happening on the animation finished callback are happening on the global
+                // transaction.
+                // For now we need to run this after it's guaranteed that the transaction that
+                // reparents the surface onto the leash is executed already. Otherwise this may be
+                // executed first, leading to surface loss, as the reparent operations wouldn't
+                // be in order.
+                addAfterPrepareSurfaces.accept(() -> {
+                    if (anim != mAnimation) {
+                        // Callback was from another animation - ignore.
+                        return;
+                    }
+                    final Transaction t = new Transaction();
+                    SurfaceControl.openTransaction();
+                    try {
+                        reset(t, true /* destroyLeash */);
+                        if (animationFinishedCallback != null) {
+                            animationFinishedCallback.run();
+                        }
+                    } finally {
+                        SurfaceControl.mergeToGlobalTransaction(t);
+                        SurfaceControl.closeTransaction();
+                    }
+                });
             }
         };
     }
@@ -268,7 +290,7 @@
         }
         mService.mAnimationTransferMap.remove(mAnimation);
         if (mLeash != null && destroyLeash) {
-            t.destroy(mLeash);
+            mAnimatable.destroyAfterPendingTransaction(mLeash);
         }
         mLeash = null;
         mAnimation = null;
@@ -357,6 +379,13 @@
         void onAnimationLeashDestroyed(Transaction t);
 
         /**
+         * Destroy a given surface after executing {@link #getPendingTransaction}.
+         *
+         * @see WindowContainer#destroyAfterPendingTransaction
+         */
+        void destroyAfterPendingTransaction(SurfaceControl surface);
+
+        /**
          * @return A new surface to be used for the animation leash, inserted at the correct
          *         position in the hierarchy.
          */
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index ab10197..20349b9 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -226,6 +226,13 @@
                 if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
             }
 
+            final int numDisplays = mDisplayContentsAnimators.size();
+            for (int i = 0; i < numDisplays; i++) {
+                final int displayId = mDisplayContentsAnimators.keyAt(i);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
+                dc.onPendingTransactionApplied();
+            }
+
             boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
             boolean doRequest = false;
             if (mBulkUpdateParams != 0) {
@@ -259,6 +266,7 @@
             }
 
             mService.destroyPreservedSurfaceLocked();
+            mService.mWindowPlacerLocked.destroyPendingSurfaces();
 
             executeAfterPrepareSurfacesRunnables();
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 93e9137..1f7caff 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -109,7 +109,8 @@
     WindowContainer(WindowManagerService service) {
         mService = service;
         mPendingTransaction = service.mTransactionFactory.make();
-        mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
+        mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
+                service.mAnimator::addAfterPrepareSurfacesRunnable, service);
     }
 
     @Override
@@ -285,9 +286,8 @@
         }
 
         if (mSurfaceControl != null) {
-            getPendingTransaction().destroy(mSurfaceControl);
+            destroyAfterPendingTransaction(mSurfaceControl);
             mSurfaceControl = null;
-            scheduleAnimation();
         }
 
         if (mParent != null) {
@@ -1075,6 +1075,19 @@
         return mSurfaceControl;
     }
 
+    /**
+     * Destroy a given surface after executing mPendingTransaction. This is
+     * largely a workaround for destroy not being part of transactions
+     * rather than an intentional design, so please take care when
+     * expanding use.
+     */
+    @Override
+    public void destroyAfterPendingTransaction(SurfaceControl surface) {
+        if (mParent != null) {
+            mParent.destroyAfterPendingTransaction(surface);
+        }
+    }
+
     @Override
     public Transaction getPendingTransaction() {
         return mPendingTransaction;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c1a1452..21b4361 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4067,9 +4067,7 @@
 
         final boolean hasSurface = mWinAnimator.hasSurface();
         if (hasSurface) {
-            // Use pendingTransaction here so hide is done the same transaction as the other
-            // animations when exiting
-            mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");
+            mWinAnimator.hide("onExitAnimationDone");
         }
 
         // If we have an app token, we ask it to destroy the surface for us, so that it can take
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index a699ba0..9621ee5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -164,8 +164,6 @@
 
     private boolean mAnimationStartDelayed;
 
-    private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
-
     /** The pixel format of the underlying SurfaceControl */
     int mSurfaceFormat;
 
@@ -282,21 +280,16 @@
         }
     }
 
-    void hide(SurfaceControl.Transaction transaction, String reason) {
+    void hide(String reason) {
         if (!mLastHidden) {
             //dump();
             mLastHidden = true;
             if (mSurfaceController != null) {
-                mSurfaceController.hide(transaction, reason);
+                mSurfaceController.hideInTransaction(reason);
             }
         }
     }
 
-    void hide(String reason) {
-        hide(mTmpTransaction, reason);
-        SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
-    }
-
     boolean finishDrawingLocked() {
         final boolean startingWindow =
                 mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index d88e59c..554a600 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -86,8 +86,6 @@
     private final int mWindowType;
     private final Session mWindowSession;
 
-    private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
-
     public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
             int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
         mAnimator = animator;
@@ -150,23 +148,21 @@
         }
     }
 
-    void hide(SurfaceControl.Transaction transaction, String reason) {
+    void hideInTransaction(String reason) {
         if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
         mHiddenForOtherReasons = true;
 
         mAnimator.destroyPreservedSurfaceLocked();
-        if (mSurfaceShown) {
-            hideSurface(transaction);
-        }
+        updateVisibility();
     }
 
-    private void hideSurface(SurfaceControl.Transaction transaction) {
+    private void hideSurface() {
         if (mSurfaceControl == null) {
             return;
         }
         setShown(false);
         try {
-            transaction.hide(mSurfaceControl);
+            mSurfaceControl.hide();
         } catch (RuntimeException e) {
             Slog.w(TAG, "Exception hiding surface in " + this);
         }
@@ -425,8 +421,7 @@
     private boolean updateVisibility() {
         if (mHiddenForCrop || mHiddenForOtherReasons) {
             if (mSurfaceShown) {
-                hideSurface(mTmpTransaction);
-                SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
+                hideSurface();
             }
             return false;
         } else {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 272f3a5..7364e87 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -102,6 +102,7 @@
     }
     private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
 
+    private final ArrayList<SurfaceControl> mPendingDestroyingSurfaces = new ArrayList<>();
     private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
 
     private final Runnable mPerformSurfacePlacement;
@@ -696,6 +697,25 @@
         }
     }
 
+    /**
+     * Puts the {@param surface} into a pending list to be destroyed after the current transaction
+     * has been committed.
+     */
+    void destroyAfterTransaction(SurfaceControl surface) {
+        mPendingDestroyingSurfaces.add(surface);
+    }
+
+    /**
+     * Destroys any surfaces that have been put into the pending list with
+     * {@link #destroyAfterTransaction}.
+     */
+    void destroyPendingSurfaces() {
+        for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
+            mPendingDestroyingSurfaces.get(i).destroy();
+        }
+        mPendingDestroyingSurfaces.clear();
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
         pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 79a9610..b55c79b 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -131,6 +131,7 @@
             assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
 
             controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
+            mDisplayContent.onPendingTransactionApplied();
         }
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index a120eba..64c3037 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -23,11 +23,11 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 
 import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.SurfaceControl;
@@ -39,6 +39,7 @@
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -46,6 +47,7 @@
 import org.mockito.MockitoAnnotations;
 
 import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
 
 /**
  * Test class for {@link SurfaceAnimatorTest}.
@@ -85,7 +87,7 @@
         callbackCaptor.getValue().onAnimationFinished(mSpec);
         assertNotAnimating(mAnimatable);
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
         // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
     }
 
@@ -95,7 +97,7 @@
         final SurfaceControl firstLeash = mAnimatable.mLeash;
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
 
-        verify(mTransaction).destroy(eq(firstLeash));
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
         assertFalse(mAnimatable.mFinishedCallbackCalled);
 
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -122,7 +124,7 @@
         assertNotAnimating(mAnimatable);
         verify(mSpec).onAnimationCancelled(any());
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
     }
 
     @Test
@@ -143,7 +145,7 @@
         verifyZeroInteractions(mSpec);
         assertNotAnimating(mAnimatable);
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(mAnimatable.mLeash));
+        assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
     }
 
     @Test
@@ -159,11 +161,11 @@
         assertNotAnimating(mAnimatable);
         assertAnimating(mAnimatable2);
         assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
-        verify(mTransaction, never()).destroy(eq(leash));
+        assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
         callbackCaptor.getValue().onAnimationFinished(mSpec);
         assertNotAnimating(mAnimatable2);
         assertTrue(mAnimatable2.mFinishedCallbackCalled);
-        verify(mTransaction).destroy(eq(leash));
+        assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
     }
 
     private void assertAnimating(MyAnimatable animatable) {
@@ -180,6 +182,7 @@
 
         final SurfaceControl mParent;
         final SurfaceControl mSurface;
+        final ArrayList<SurfaceControl> mPendingDestroySurfaces = new ArrayList<>();
         final SurfaceAnimator mSurfaceAnimator;
         SurfaceControl mLeash;
         boolean mFinishedCallbackCalled;
@@ -195,7 +198,7 @@
                     .build();
             mFinishedCallbackCalled = false;
             mLeash = null;
-            mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
+            mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, Runnable::run, sWm);
         }
 
         @Override
@@ -216,6 +219,11 @@
         }
 
         @Override
+        public void destroyAfterPendingTransaction(SurfaceControl surface) {
+            mPendingDestroySurfaces.add(surface);
+        }
+
+        @Override
         public Builder makeAnimationLeash() {
             return new SurfaceControl.Builder(mSession) {
 
diff --git a/services/usb/OWNERS b/services/usb/OWNERS
new file mode 100644
index 0000000..7897a0c
--- /dev/null
+++ b/services/usb/OWNERS
@@ -0,0 +1,4 @@
+badhri@google.com
+elaurent@google.com
+moltmann@google.com
+zhangjerry@google.com
diff --git a/telecomm/OWNERS b/telecomm/OWNERS
new file mode 100644
index 0000000..a3bcfb2
--- /dev/null
+++ b/telecomm/OWNERS
@@ -0,0 +1,6 @@
+set noparent
+
+tgunn@google.com
+breadley@google.com
+hallliu@google.com
+rgreenwalt@google.com
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 8c18518..0c92c20 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -425,8 +425,14 @@
          */
         public static final int PROPERTY_ASSISTED_DIALING_USED = 0x00000200;
 
+        /**
+         * Indicates that the call is an RTT call. Use {@link #getRttCall()} to get the
+         * {@link RttCall} object that is used to send and receive text.
+         */
+        public static final int PROPERTY_RTT = 0x00000400;
+
         //******************************************************************************************
-        // Next PROPERTY value: 0x00000400
+        // Next PROPERTY value: 0x00000800
         //******************************************************************************************
 
         private final String mTelecomCallId;
@@ -1189,6 +1195,23 @@
                 return null;
             }
         }
+
+        /**
+         * Closes the underlying file descriptors
+         * @hide
+         */
+        public void close() {
+            try {
+                mReceiveStream.close();
+            } catch (IOException e) {
+                // ignore
+            }
+            try {
+                mTransmitStream.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
     }
 
     /**
@@ -1664,7 +1687,7 @@
      * @return true if there is a connection, false otherwise.
      */
     public boolean isRttActive() {
-        return mRttCall != null;
+        return mRttCall != null && mDetails.hasProperty(Details.PROPERTY_RTT);
     }
 
     /**
@@ -1867,7 +1890,8 @@
 
         boolean isRttChanged = false;
         boolean rttModeChanged = false;
-        if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
+        if (parcelableCall.getIsRttCallChanged()
+                && mDetails.hasProperty(Details.PROPERTY_RTT)) {
             ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
             InputStreamReader receiveStream = new InputStreamReader(
                     new ParcelFileDescriptor.AutoCloseInputStream(
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 3229705..26a2f1c 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -41,6 +41,8 @@
 import android.util.ArraySet;
 import android.view.Surface;
 
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
@@ -860,18 +862,19 @@
             mFdFromInCall = fromInCall;
             mFdToInCall = toInCall;
             mPipeFromInCall = new InputStreamReader(
-                    new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
+                    new FileInputStream(fromInCall.getFileDescriptor()));
             mPipeToInCall = new OutputStreamWriter(
-                    new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
+                    new FileOutputStream(toInCall.getFileDescriptor()));
         }
 
         /**
          * Writes the string {@param input} into the text stream to the UI for this RTT call. Since
          * RTT transmits text in real-time, this method should be called as often as text snippets
          * are received from the remote user, even if it is only one character.
-         *
+         * <p>
          * This method is not thread-safe -- calling it from multiple threads simultaneously may
          * lead to interleaved text.
+         *
          * @param input The message to send to the in-call app.
          */
         public void write(String input) throws IOException {
@@ -884,9 +887,10 @@
          * Reads a string from the in-call app, blocking if there is no data available. Returns
          * {@code null} if the RTT conversation has been terminated and there is no further data
          * to read.
-         *
+         * <p>
          * This method is not thread-safe -- calling it from multiple threads simultaneously may
          * lead to interleaved text.
+         *
          * @return A string containing text entered by the user, or {@code null} if the
          * conversation has been terminated or if there was an error while reading.
          */
@@ -901,6 +905,7 @@
         /**
          * Non-blocking version of {@link #read()}. Returns {@code null} if there is nothing to
          * be read.
+         *
          * @return A string containing text entered by the user, or {@code null} if the user has
          * not entered any new text yet.
          */
@@ -2635,7 +2640,6 @@
      * {@link #onStartRtt(RttTextStream)} has succeeded.
      */
     public final void sendRttInitiationSuccess() {
-        setRttProperty();
         mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
     }
 
@@ -2647,7 +2651,6 @@
      *               exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
      */
     public final void sendRttInitiationFailure(int reason) {
-        unsetRttProperty();
         mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
     }
 
@@ -2656,7 +2659,6 @@
      * side of the coll.
      */
     public final void sendRttSessionRemotelyTerminated() {
-        unsetRttProperty();
         mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
     }
 
@@ -2956,22 +2958,6 @@
      */
     public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
 
-    /**
-     * Internal method to set {@link #PROPERTY_IS_RTT}.
-     * @hide
-     */
-    void setRttProperty() {
-        setConnectionProperties(getConnectionProperties() | PROPERTY_IS_RTT);
-    }
-
-    /**
-     * Internal method to un-set {@link #PROPERTY_IS_RTT}.
-     * @hide
-     */
-    void unsetRttProperty() {
-        setConnectionProperties(getConnectionProperties() & (~PROPERTY_IS_RTT));
-    }
-
     static String toLogSafePhoneNumber(String number) {
         // For unknown number, log empty string.
         if (number == null) {
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 658b473..b6e6b0e 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -143,6 +143,8 @@
     private final boolean mShouldShowIncomingCallUi;
     private final ParcelFileDescriptor mRttPipeToInCall;
     private final ParcelFileDescriptor mRttPipeFromInCall;
+    // Cached return value of getRttTextStream -- we don't want to wrap it more than once.
+    private Connection.RttTextStream mRttTextStream;
 
     /**
      * @param accountHandle The accountHandle which should be used to place the call.
@@ -312,7 +314,10 @@
      */
     public Connection.RttTextStream getRttTextStream() {
         if (isRequestingRtt()) {
-            return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+            if (mRttTextStream == null) {
+                mRttTextStream = new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+            }
+            return mRttTextStream;
         } else {
             return null;
         }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 1547857..ffa0c94 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -143,6 +143,7 @@
     private static final String SESSION_HANDOVER_COMPLETE = "CS.hC";
     private static final String SESSION_EXTRAS_CHANGED = "CS.oEC";
     private static final String SESSION_START_RTT = "CS.+RTT";
+    private static final String SESSION_UPDATE_RTT_PIPES = "CS.uRTT";
     private static final String SESSION_STOP_RTT = "CS.-RTT";
     private static final String SESSION_RTT_UPGRADE_RESPONSE = "CS.rTRUR";
     private static final String SESSION_CONNECTION_SERVICE_FOCUS_LOST = "CS.cSFL";
@@ -1864,7 +1865,6 @@
         Log.d(this, "stopRtt(%s)", callId);
         if (mConnectionById.containsKey(callId)) {
             findConnectionForAction(callId, "stopRtt").onStopRtt();
-            findConnectionForAction(callId, "stopRtt").unsetRttProperty();
         } else if (mConferenceById.containsKey(callId)) {
             Log.w(this, "stopRtt called on a conference.");
         }
diff --git a/telephony/java/android/telephony/OWNERS b/telephony/OWNERS
similarity index 92%
copy from telephony/java/android/telephony/OWNERS
copy to telephony/OWNERS
index 68dedce..6f67bc2 100644
--- a/telephony/java/android/telephony/OWNERS
+++ b/telephony/OWNERS
@@ -1,14 +1,14 @@
 set noparent
 
-amitmahajan@google.com
+tgunn@google.com
 breadley@google.com
-fionaxu@google.com
-jackyu@google.com
 hallliu@google.com
 rgreenwalt@google.com
-tgunn@google.com
-jminjie@google.com
 mpq@google.com
+amitmahajan@google.com
+fionaxu@google.com
+jackyu@google.com
+jminjie@google.com
+satk@google.com
 shuoq@google.com
 refuhoo@google.com
-
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index f009fb1..7e86966 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -172,7 +172,7 @@
     }
 
     /**
-     * Get the timing advance value for LTE, as a value between 0..63.
+     * Get the timing advance value for LTE, as a value in range of 0..1282.
      * Integer.MAX_VALUE is reported when there is no active RRC
      * connection. Refer to 3GPP 36.213 Sec 4.2.3
      * @return the LTE timing advance, if available.
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index cb867ab..ec348df 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1526,7 +1526,9 @@
      */
     @SystemApi
     public List<NetworkRegistrationState> getNetworkRegistrationStates() {
-        return mNetworkRegistrationStates;
+        synchronized (mNetworkRegistrationStates) {
+            return new ArrayList<>(mNetworkRegistrationStates);
+        }
     }
 
     /**
@@ -1539,11 +1541,15 @@
     @SystemApi
     public List<NetworkRegistrationState> getNetworkRegistrationStates(int transportType) {
         List<NetworkRegistrationState> list = new ArrayList<>();
-        for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
-            if (networkRegistrationState.getTransportType() == transportType) {
-                list.add(networkRegistrationState);
+
+        synchronized (mNetworkRegistrationStates) {
+            for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+                if (networkRegistrationState.getTransportType() == transportType) {
+                    list.add(networkRegistrationState);
+                }
             }
         }
+
         return list;
     }
 
@@ -1557,12 +1563,36 @@
      */
     @SystemApi
     public NetworkRegistrationState getNetworkRegistrationStates(int transportType, int domain) {
-        for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
-            if (networkRegistrationState.getTransportType() == transportType
-                    && networkRegistrationState.getDomain() == domain) {
-                return networkRegistrationState;
+        synchronized (mNetworkRegistrationStates) {
+            for (NetworkRegistrationState networkRegistrationState : mNetworkRegistrationStates) {
+                if (networkRegistrationState.getTransportType() == transportType
+                        && networkRegistrationState.getDomain() == domain) {
+                    return networkRegistrationState;
+                }
             }
         }
+
         return null;
     }
+
+    /**
+     * @hide
+     */
+    public void addNetworkRegistrationState(NetworkRegistrationState regState) {
+        if (regState == null) return;
+
+        synchronized (mNetworkRegistrationStates) {
+            for (int i = 0; i < mNetworkRegistrationStates.size(); i++) {
+                NetworkRegistrationState curRegState = mNetworkRegistrationStates.get(i);
+                if (curRegState.getTransportType() == regState.getTransportType()
+                        && curRegState.getDomain() == regState.getDomain()) {
+                    mNetworkRegistrationStates.remove(i);
+                    break;
+                }
+            }
+
+            mNetworkRegistrationStates.add(regState);
+        }
+    }
+
 }
diff --git a/tests/ActivityManagerPerfTests/test-app/Android.mk b/tests/ActivityManagerPerfTests/test-app/Android.mk
index b0a5db7..767e899 100644
--- a/tests/ActivityManagerPerfTests/test-app/Android.mk
+++ b/tests/ActivityManagerPerfTests/test-app/Android.mk
@@ -23,6 +23,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     ActivityManagerPerfTestsUtils
 
+LOCAL_MIN_SDK_VERSION := 25
+
 LOCAL_PACKAGE_NAME := ActivityManagerPerfTestsTestApp
 
 include $(BUILD_PACKAGE)
diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk
index daf603d..7597e69 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.mk
+++ b/tests/ActivityManagerPerfTests/tests/Android.mk
@@ -27,6 +27,8 @@
 
 LOCAL_PACKAGE_NAME := ActivityManagerPerfTests
 
+LOCAL_MIN_SDK_VERSION := 25
+
 # For android.permission.FORCE_STOP_PACKAGES permission
 LOCAL_CERTIFICATE := platform
 
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 228f9bb..83354d5 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -302,7 +302,7 @@
                         atraceLogger.atraceStop();
                     }
                 }
-                closeApp(launch.getApp(), true);
+                closeApp(launch.getApp());
                 sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
             }
         } finally {
@@ -575,22 +575,23 @@
         }
     }
 
-    private void closeApp(String appName, boolean forceStopApp) {
+    private void startHomeIntent() {
         Intent homeIntent = new Intent(Intent.ACTION_MAIN);
         homeIntent.addCategory(Intent.CATEGORY_HOME);
         homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                 | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         getInstrumentation().getContext().startActivity(homeIntent);
         sleep(POST_LAUNCH_IDLE_TIMEOUT);
-        if (forceStopApp) {
-            Intent startIntent = mNameToIntent.get(appName);
-            if (startIntent != null) {
-                String packageName = startIntent.getComponent().getPackageName();
-                try {
-                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
-                } catch (RemoteException e) {
-                    Log.w(TAG, "Error closing app", e);
-                }
+    }
+
+    private void closeApp(String appName) {
+        Intent startIntent = mNameToIntent.get(appName);
+        if (startIntent != null) {
+            String packageName = startIntent.getComponent().getPackageName();
+            try {
+                mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error closing app", e);
             }
         }
     }
diff --git a/tests/AppLaunchWear/Android.mk b/tests/AppLaunchWear/Android.mk
new file mode 100644
index 0000000..ac123e7
--- /dev/null
+++ b/tests/AppLaunchWear/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := AppLaunchWear
+
+LOCAL_CERTIFICATE := platform
+LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_COMPATIBILITY_SUITE := device-tests
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AppLaunchWear/AndroidManifest.xml b/tests/AppLaunchWear/AndroidManifest.xml
new file mode 100644
index 0000000..7dfd7ba
--- /dev/null
+++ b/tests/AppLaunchWear/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.tests.applaunch"
+    android:sharedUserId="android.uid.system" >
+
+   <uses-permission android:name="android.permission.REAL_GET_TASKS" />
+   <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+   <uses-sdk
+        android:minSdkVersion="22"
+        android:targetSdkVersion="24" />
+
+    <instrumentation android:label="Measure app start up time"
+                     android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="com.android.tests.applaunch" />
+
+    <application android:label="App Launch Test">
+        <uses-library android:name="android.test.runner" />
+    </application>
+</manifest>
diff --git a/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java
new file mode 100644
index 0000000..f32464b
--- /dev/null
+++ b/tests/AppLaunchWear/src/com/android/tests/applaunch/AppLaunch.java
@@ -0,0 +1,821 @@
+/*
+ * Copyright (C) 2013 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.tests.applaunch;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.ActivityManager;
+import android.app.ActivityManager.ProcessErrorStateInfo;
+import android.app.IActivityManager;
+import android.app.UiAutomation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.support.test.rule.logging.AtraceLogger;
+import android.test.InstrumentationTestCase;
+import android.test.InstrumentationTestRunner;
+import android.util.Log;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+/**
+ * This test is intended to measure the time it takes for the apps to start.
+ * Names of the applications are passed in command line, and the
+ * test starts each application, and reports the start up time in milliseconds.
+ * The instrumentation expects the following key to be passed on the command line:
+ * apps - A list of applications to start and their corresponding result keys
+ * in the following format:
+ * -e apps <app name>^<result key>|<app name>^<result key>
+ */
+public class AppLaunch extends InstrumentationTestCase {
+
+    private static final int JOIN_TIMEOUT = 10000;
+    private static final String TAG = AppLaunch.class.getSimpleName();
+
+    // optional parameter: comma separated list of required account types before proceeding
+    // with the app launch
+    private static final String KEY_REQUIRED_ACCOUNTS = "required_accounts";
+    private static final String KEY_APPS = "apps";
+    private static final String KEY_TRIAL_LAUNCH = "trial_launch";
+    private static final String KEY_LAUNCH_ITERATIONS = "launch_iterations";
+    private static final String KEY_LAUNCH_ORDER = "launch_order";
+    private static final String KEY_DROP_CACHE = "drop_cache";
+    private static final String KEY_SIMPLEPERF_CMD = "simpleperf_cmd";
+    private static final String KEY_SIMPLEPERF_APP = "simpleperf_app";
+    private static final String KEY_TRACE_ITERATIONS = "trace_iterations";
+    private static final String KEY_LAUNCH_DIRECTORY = "launch_directory";
+    private static final String KEY_TRACE_DIRECTORY = "trace_directory";
+    private static final String KEY_TRACE_CATEGORY = "trace_categories";
+    private static final String KEY_TRACE_BUFFERSIZE = "trace_bufferSize";
+    private static final String KEY_TRACE_DUMPINTERVAL = "tracedump_interval";
+    private static final String KEY_COMPILER_FILTERS = "compiler_filters";
+
+    private static final String SIMPLEPERF_APP_CMD =
+            "simpleperf --log fatal stat --csv -e cpu-cycles,major-faults --app %s & %s";
+    private static final String WEARABLE_ACTION_GOOGLE =
+            "com.google.android.wearable.action.GOOGLE";
+    private static final int INITIAL_LAUNCH_IDLE_TIMEOUT = 5000; // 5s to allow app to idle
+    private static final int POST_LAUNCH_IDLE_TIMEOUT = 750; // 750ms idle for non initial launches
+    private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 5000; // 5s between launching apps
+    private static final String LAUNCH_SUB_DIRECTORY = "launch_logs";
+    private static final String LAUNCH_FILE = "applaunch.txt";
+    private static final String TRACE_SUB_DIRECTORY = "atrace_logs";
+    private static final String DEFAULT_TRACE_CATEGORIES =
+            "sched,freq,gfx,view,dalvik,webview,input,wm,disk,am,wm";
+    private static final String DEFAULT_TRACE_BUFFER_SIZE = "20000";
+    private static final String DEFAULT_TRACE_DUMP_INTERVAL = "10";
+    private static final String TRIAL_LAUNCH = "TRIAL_LAUNCH";
+    private static final String DELIMITER = ",";
+    private static final String DROP_CACHE_SCRIPT = "/data/local/tmp/dropCache.sh";
+    private static final String APP_LAUNCH_CMD = "am start -W -n";
+    private static final String SUCCESS_MESSAGE = "Status: ok";
+    private static final String COMPILE_SUCCESS = "Success";
+    private static final String THIS_TIME = "ThisTime:";
+    private static final String LAUNCH_ITERATION = "LAUNCH_ITERATION - %d";
+    private static final String TRACE_ITERATION = "TRACE_ITERATION-%d";
+    private static final String LAUNCH_ITERATION_PREFIX = "LAUNCH_ITERATION";
+    private static final String TRACE_ITERATION_PREFIX = "TRACE_ITERATION";
+    private static final String LAUNCH_ORDER_CYCLIC = "cyclic";
+    private static final String LAUNCH_ORDER_SEQUENTIAL = "sequential";
+    private static final String COMPILE_CMD = "cmd package compile -f -m %s %s";
+    private static final String SPEED_PROFILE_FILTER = "speed-profile";
+    private static final String VERIFY_FILTER = "verify";
+    private static final String LAUNCH_SCRIPT_NAME = "appLaunch";
+    private static final String WEARABLE_HOME_PACKAGE = "com.google.android.wearable.app";
+
+    private Map<String, Intent> mNameToIntent;
+    private List<LaunchOrder> mLaunchOrderList = new ArrayList<LaunchOrder>();
+    private Map<String, String> mNameToResultKey;
+    private Map<String, Map<String, List<AppLaunchResult>>> mNameToLaunchTime;
+    private IActivityManager mAm;
+    private String mSimplePerfCmd = null;
+    private String mLaunchOrder = null;
+    private boolean mDropCache = false;
+    private int mLaunchIterations = 10;
+    private int mTraceLaunchCount = 0;
+    private String mTraceDirectoryStr = null;
+    private Bundle mResult = new Bundle();
+    private Set<String> mRequiredAccounts;
+    private boolean mTrialLaunch = false;
+    private BufferedWriter mBufferedWriter = null;
+    private boolean mSimplePerfAppOnly = false;
+    private String[] mCompilerFilters = null;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_FREEZE_0);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getInstrumentation().getUiAutomation().setRotation(UiAutomation.ROTATION_UNFREEZE);
+        super.tearDown();
+    }
+
+    private void addLaunchResult(LaunchOrder launch, AppLaunchResult result) {
+        mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter()).add(result);
+    }
+
+    private boolean hasFailureOnFirstLaunch(LaunchOrder launch) {
+        List<AppLaunchResult> results =
+            mNameToLaunchTime.get(launch.getApp()).get(launch.getCompilerFilter());
+        return (results.size() > 0) && (results.get(0).mLaunchTime < 0);
+    }
+
+    public void testMeasureStartUpTime() throws RemoteException, NameNotFoundException,
+            IOException, InterruptedException {
+        InstrumentationTestRunner instrumentation =
+                (InstrumentationTestRunner)getInstrumentation();
+        Bundle args = instrumentation.getArguments();
+        mAm = ActivityManager.getService();
+        String launchDirectory = args.getString(KEY_LAUNCH_DIRECTORY);
+
+        createMappings();
+        parseArgs(args);
+        checkAccountSignIn();
+
+        // Root directory for applaunch file to log the app launch output
+        // Will be useful in case of simpleperf command is used
+        File launchRootDir = null;
+        if (null != launchDirectory && !launchDirectory.isEmpty()) {
+            launchRootDir = new File(launchDirectory);
+            if (!launchRootDir.exists() && !launchRootDir.mkdirs()) {
+                throw new IOException("Unable to create the destination directory");
+            }
+        }
+
+        try {
+            File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
+
+            if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
+                throw new IOException("Unable to create the lauch file sub directory");
+            }
+            File file = new File(launchSubDir, LAUNCH_FILE);
+            FileOutputStream outputStream = new FileOutputStream(file);
+            mBufferedWriter = new BufferedWriter(new OutputStreamWriter(
+                    outputStream));
+
+            // Root directory for trace file during the launches
+            File rootTrace = null;
+            File rootTraceSubDir = null;
+            int traceBufferSize = 0;
+            int traceDumpInterval = 0;
+            Set<String> traceCategoriesSet = null;
+            if (null != mTraceDirectoryStr && !mTraceDirectoryStr.isEmpty()) {
+                rootTrace = new File(mTraceDirectoryStr);
+                if (!rootTrace.exists() && !rootTrace.mkdirs()) {
+                    throw new IOException("Unable to create the trace directory");
+                }
+                rootTraceSubDir = new File(rootTrace, TRACE_SUB_DIRECTORY);
+                if (!rootTraceSubDir.exists() && !rootTraceSubDir.mkdirs()) {
+                    throw new IOException("Unable to create the trace sub directory");
+                }
+                assertNotNull("Trace iteration parameter is mandatory",
+                        args.getString(KEY_TRACE_ITERATIONS));
+                mTraceLaunchCount = Integer.parseInt(args.getString(KEY_TRACE_ITERATIONS));
+                String traceCategoriesStr = args
+                        .getString(KEY_TRACE_CATEGORY, DEFAULT_TRACE_CATEGORIES);
+                traceBufferSize = Integer.parseInt(args.getString(KEY_TRACE_BUFFERSIZE,
+                        DEFAULT_TRACE_BUFFER_SIZE));
+                traceDumpInterval = Integer.parseInt(args.getString(KEY_TRACE_DUMPINTERVAL,
+                        DEFAULT_TRACE_DUMP_INTERVAL));
+                traceCategoriesSet = new HashSet<String>();
+                if (!traceCategoriesStr.isEmpty()) {
+                    String[] traceCategoriesSplit = traceCategoriesStr.split(DELIMITER);
+                    for (int i = 0; i < traceCategoriesSplit.length; i++) {
+                        traceCategoriesSet.add(traceCategoriesSplit[i]);
+                    }
+                }
+            }
+
+            // Get the app launch order based on launch order, trial launch,
+            // launch iterations and trace iterations
+            setLaunchOrder();
+
+            for (LaunchOrder launch : mLaunchOrderList) {
+                dropCache();
+                String appPkgName = mNameToIntent.get(launch.getApp())
+                        .getComponent().getPackageName();
+
+                // App launch times for trial launch will not be used for final
+                // launch time calculations.
+                if (launch.getLaunchReason().equals(TRIAL_LAUNCH)) {
+                    // In the "applaunch.txt" file, trail launches is referenced using
+                    // "TRIAL_LAUNCH"
+                    if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+                        assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+                              compileApp(VERIFY_FILTER, appPkgName));
+                    } else if (launch.getCompilerFilter() != null) {
+                        assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+                              compileApp(launch.getCompilerFilter(), appPkgName));
+                    }
+                    // We only need to run a trial for the speed-profile filter, but we always
+                    // run one for "applaunch.txt" consistency.
+                    AppLaunchResult launchResult =
+                        startApp(launch.getApp(), true, launch.getLaunchReason());
+                    if (launchResult.mLaunchTime < 0) {
+                        addLaunchResult(launch, new AppLaunchResult());
+                        // simply pass the app if launch isn't successful
+                        // error should have already been logged by startApp
+                        continue;
+                    }
+                    sleep(INITIAL_LAUNCH_IDLE_TIMEOUT);
+                    if (SPEED_PROFILE_FILTER.equals(launch.getCompilerFilter())) {
+                        // Send SIGUSR1 to force dumping a profile.
+                        String sendSignalCommand =
+                            String.format("killall -s SIGUSR1 %s", appPkgName);
+                        getInstrumentation().getUiAutomation().executeShellCommand(
+                            sendSignalCommand);
+                        assertTrue(String.format("Not able to compile the app : %s", appPkgName),
+                              compileApp(launch.getCompilerFilter(), appPkgName));
+                    }
+                }
+
+                // App launch times used for final calculation
+                else if (launch.getLaunchReason().contains(LAUNCH_ITERATION_PREFIX)) {
+                    AppLaunchResult launchResults = null;
+                    if (hasFailureOnFirstLaunch(launch)) {
+                        // skip if the app has failures while launched first
+                        continue;
+                    }
+                    // In the "applaunch.txt" file app launches are referenced using
+                    // "LAUNCH_ITERATION - ITERATION NUM"
+                    if (appPkgName.contains(WEARABLE_HOME_PACKAGE)) {
+                        launchResults = startApp(launch.getApp(), false, launch.getLaunchReason());
+                    } else {
+                        launchResults = startApp(launch.getApp(), true, launch.getLaunchReason());
+                    }
+                    if (launchResults.mLaunchTime < 0) {
+                        addLaunchResult(launch, new AppLaunchResult());
+                        // if it fails once, skip the rest of the launches
+                        continue;
+                    } else {
+                        addLaunchResult(launch, launchResults);
+                    }
+                    sleep(POST_LAUNCH_IDLE_TIMEOUT);
+                }
+
+                // App launch times for trace launch will not be used for final
+                // launch time calculations.
+                else if (launch.getLaunchReason().contains(TRACE_ITERATION_PREFIX)) {
+                    AtraceLogger atraceLogger = AtraceLogger
+                            .getAtraceLoggerInstance(getInstrumentation());
+                    // Start the trace
+                    try {
+                        atraceLogger.atraceStart(traceCategoriesSet, traceBufferSize,
+                                traceDumpInterval, rootTraceSubDir,
+                                String.format("%s-%s", launch.getApp(), launch.getLaunchReason()));
+                        startApp(launch.getApp(), true, launch.getLaunchReason());
+                        sleep(POST_LAUNCH_IDLE_TIMEOUT);
+                    } finally {
+                        // Stop the trace
+                        atraceLogger.atraceStop();
+                    }
+                }
+                closeApp(launch.getApp(), true);
+                sleep(BETWEEN_LAUNCH_SLEEP_TIMEOUT);
+            }
+        } finally {
+            if (null != mBufferedWriter) {
+                mBufferedWriter.close();
+            }
+        }
+
+        for (String app : mNameToResultKey.keySet()) {
+            for (String compilerFilter : mCompilerFilters) {
+                StringBuilder launchTimes = new StringBuilder();
+                StringBuilder cpuCycles = new StringBuilder();
+                StringBuilder majorFaults = new StringBuilder();
+                for (AppLaunchResult result : mNameToLaunchTime.get(app).get(compilerFilter)) {
+                    launchTimes.append(result.mLaunchTime);
+                    launchTimes.append(",");
+                    if (mSimplePerfAppOnly) {
+                        cpuCycles.append(result.mCpuCycles);
+                        cpuCycles.append(",");
+                        majorFaults.append(result.mMajorFaults);
+                        majorFaults.append(",");
+                    }
+                }
+                String filterName = (compilerFilter == null) ? "" : ("-" + compilerFilter);
+                mResult.putString(mNameToResultKey.get(app) + filterName, launchTimes.toString());
+                if (mSimplePerfAppOnly) {
+                    mResult.putString(mNameToResultKey.get(app) + filterName + "-cpuCycles",
+                        cpuCycles.toString());
+                    mResult.putString(mNameToResultKey.get(app) + filterName + "-majorFaults",
+                        majorFaults.toString());
+                }
+            }
+        }
+        instrumentation.sendStatus(0, mResult);
+    }
+
+    /**
+     * Compile the app package using compilerFilter and return true or false
+     * based on status of the compilation command.
+     */
+    private boolean compileApp(String compilerFilter, String appPkgName) throws IOException {
+        try (ParcelFileDescriptor result = getInstrumentation().getUiAutomation().
+                executeShellCommand(String.format(COMPILE_CMD, compilerFilter, appPkgName));
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+                        new FileInputStream(result.getFileDescriptor())))) {
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                if (line.contains(COMPILE_SUCCESS)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * If launch order is "cyclic" then apps will be launched one after the
+     * other for each iteration count.
+     * If launch order is "sequential" then each app will be launched for given number
+     * iterations at once before launching the other apps.
+     */
+    private void setLaunchOrder() {
+        if (LAUNCH_ORDER_CYCLIC.equalsIgnoreCase(mLaunchOrder)) {
+            for (String compilerFilter : mCompilerFilters) {
+                if (mTrialLaunch) {
+                    for (String app : mNameToResultKey.keySet()) {
+                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+                    }
+                }
+                for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+                    for (String app : mNameToResultKey.keySet()) {
+                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+                                  String.format(LAUNCH_ITERATION, launchCount)));
+                    }
+                }
+                if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+                    for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+                        for (String app : mNameToResultKey.keySet()) {
+                            mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+                                      String.format(TRACE_ITERATION, traceCount)));
+                        }
+                    }
+                }
+            }
+        } else if (LAUNCH_ORDER_SEQUENTIAL.equalsIgnoreCase(mLaunchOrder)) {
+            for (String compilerFilter : mCompilerFilters) {
+                for (String app : mNameToResultKey.keySet()) {
+                    if (mTrialLaunch) {
+                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter, TRIAL_LAUNCH));
+                    }
+                    for (int launchCount = 0; launchCount < mLaunchIterations; launchCount++) {
+                        mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+                                String.format(LAUNCH_ITERATION, launchCount)));
+                    }
+                    if (mTraceDirectoryStr != null && !mTraceDirectoryStr.isEmpty()) {
+                        for (int traceCount = 0; traceCount < mTraceLaunchCount; traceCount++) {
+                            mLaunchOrderList.add(new LaunchOrder(app, compilerFilter,
+                                    String.format(TRACE_ITERATION, traceCount)));
+                        }
+                    }
+                }
+            }
+        } else {
+            assertTrue("Launch order is not valid parameter", false);
+        }
+    }
+
+    private void dropCache() {
+        if (mDropCache) {
+            assertNotNull("Issue in dropping the cache",
+                    getInstrumentation().getUiAutomation()
+                            .executeShellCommand(DROP_CACHE_SCRIPT));
+        }
+    }
+
+    private void parseArgs(Bundle args) {
+        mNameToResultKey = new LinkedHashMap<String, String>();
+        mNameToLaunchTime = new HashMap<>();
+        String launchIterations = args.getString(KEY_LAUNCH_ITERATIONS);
+        if (launchIterations != null) {
+            mLaunchIterations = Integer.parseInt(launchIterations);
+        }
+        String appList = args.getString(KEY_APPS);
+        if (appList == null)
+            return;
+
+        String appNames[] = appList.split("\\|");
+        for (String pair : appNames) {
+            String[] parts = pair.split("\\^");
+            if (parts.length != 2) {
+                Log.e(TAG, "The apps key is incorrectly formatted");
+                fail();
+            }
+
+            mNameToResultKey.put(parts[0], parts[1]);
+            mNameToLaunchTime.put(parts[0], null);
+        }
+        String requiredAccounts = args.getString(KEY_REQUIRED_ACCOUNTS);
+        if (requiredAccounts != null) {
+            mRequiredAccounts = new HashSet<String>();
+            for (String accountType : requiredAccounts.split(",")) {
+                mRequiredAccounts.add(accountType);
+            }
+        }
+
+        String compilerFilterList = args.getString(KEY_COMPILER_FILTERS);
+        if (compilerFilterList != null) {
+            // If a compiler filter is passed, we make a trial launch to force compilation
+            // of the apps.
+            mTrialLaunch = true;
+            mCompilerFilters = compilerFilterList.split("\\|");
+        } else {
+            // Just pass a null compiler filter to use the current state of the app.
+            mCompilerFilters = new String[1];
+        }
+
+        // Pre-populate the results map to avoid null checks.
+        for (String app : mNameToLaunchTime.keySet()) {
+            HashMap<String, List<AppLaunchResult>> map = new HashMap<>();
+            mNameToLaunchTime.put(app, map);
+            for (String compilerFilter : mCompilerFilters) {
+                map.put(compilerFilter, new ArrayList<>());
+            }
+        }
+
+        mTraceDirectoryStr = args.getString(KEY_TRACE_DIRECTORY);
+        mDropCache = Boolean.parseBoolean(args.getString(KEY_DROP_CACHE));
+        mSimplePerfCmd = args.getString(KEY_SIMPLEPERF_CMD);
+        mLaunchOrder = args.getString(KEY_LAUNCH_ORDER, LAUNCH_ORDER_CYCLIC);
+        mSimplePerfAppOnly = Boolean.parseBoolean(args.getString(KEY_SIMPLEPERF_APP));
+        mTrialLaunch = mTrialLaunch || Boolean.parseBoolean(args.getString(KEY_TRIAL_LAUNCH));
+
+        if (mSimplePerfCmd != null && mSimplePerfAppOnly) {
+            Log.w(TAG, String.format("Passing both %s and %s is not supported, ignoring %s",
+                KEY_SIMPLEPERF_CMD, KEY_SIMPLEPERF_APP));
+        }
+    }
+
+    private boolean hasLeanback(Context context) {
+        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+    }
+
+    private void createMappings() {
+        mNameToIntent = new LinkedHashMap<String, Intent>();
+
+        PackageManager pm = getInstrumentation().getContext()
+                .getPackageManager();
+        Intent intentToResolve = new Intent(Intent.ACTION_MAIN);
+        intentToResolve.addCategory(hasLeanback(getInstrumentation().getContext()) ?
+                Intent.CATEGORY_LEANBACK_LAUNCHER :
+                Intent.CATEGORY_LAUNCHER);
+        List<ResolveInfo> ris = pm.queryIntentActivities(intentToResolve, 0);
+        resolveLoop(ris, intentToResolve, pm);
+        // For Wear
+        intentToResolve = new Intent(WEARABLE_ACTION_GOOGLE);
+        ris = pm.queryIntentActivities(intentToResolve, 0);
+        resolveLoop(ris, intentToResolve, pm);
+    }
+
+    private void resolveLoop(List<ResolveInfo> ris, Intent intentToResolve, PackageManager pm) {
+        if (ris == null || ris.isEmpty()) {
+            Log.i(TAG, "Could not find any apps");
+        } else {
+            for (ResolveInfo ri : ris) {
+                Intent startIntent = new Intent(intentToResolve);
+                startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                startIntent.setClassName(ri.activityInfo.packageName,
+                        ri.activityInfo.name);
+                String appName = ri.loadLabel(pm).toString();
+                if (appName != null) {
+                    // Support launching intent using package name or app name
+                    mNameToIntent.put(ri.activityInfo.packageName, startIntent);
+                    mNameToIntent.put(appName, startIntent);
+                }
+            }
+        }
+    }
+
+    private AppLaunchResult startApp(String appName, boolean forceStopBeforeLaunch,
+            String launchReason) throws NameNotFoundException, RemoteException {
+        Log.i(TAG, "Starting " + appName);
+
+        Intent startIntent = mNameToIntent.get(appName);
+        if (startIntent == null) {
+            Log.w(TAG, "App does not exist: " + appName);
+            mResult.putString(mNameToResultKey.get(appName), "App does not exist");
+            return new AppLaunchResult();
+        }
+        AppLaunchRunnable runnable = new AppLaunchRunnable(startIntent, forceStopBeforeLaunch,
+                launchReason);
+        Thread t = new Thread(runnable);
+        t.start();
+        try {
+            t.join(JOIN_TIMEOUT);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+        return runnable.getResult();
+    }
+
+    private void checkAccountSignIn() {
+        // ensure that the device has the required account types before starting test
+        // e.g. device must have a valid Google account sign in to measure a meaningful launch time
+        // for Gmail
+        if (mRequiredAccounts == null || mRequiredAccounts.isEmpty()) {
+            return;
+        }
+        final AccountManager am =
+                (AccountManager) getInstrumentation().getTargetContext().getSystemService(
+                        Context.ACCOUNT_SERVICE);
+        Account[] accounts = am.getAccounts();
+        // use set here in case device has multiple accounts of the same type
+        Set<String> foundAccounts = new HashSet<String>();
+        for (Account account : accounts) {
+            if (mRequiredAccounts.contains(account.type)) {
+                foundAccounts.add(account.type);
+            }
+        }
+        // check if account type matches, if not, fail test with message on what account types
+        // are missing
+        if (mRequiredAccounts.size() != foundAccounts.size()) {
+            mRequiredAccounts.removeAll(foundAccounts);
+            StringBuilder sb = new StringBuilder("Device missing these accounts:");
+            for (String account : mRequiredAccounts) {
+                sb.append(' ');
+                sb.append(account);
+            }
+            fail(sb.toString());
+        }
+    }
+
+    private void closeApp(String appName, boolean forceStopApp) {
+        Intent homeIntent = new Intent(Intent.ACTION_MAIN);
+        homeIntent.addCategory(Intent.CATEGORY_HOME);
+        homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+        getInstrumentation().getContext().startActivity(homeIntent);
+        sleep(POST_LAUNCH_IDLE_TIMEOUT);
+        if (forceStopApp) {
+            Intent startIntent = mNameToIntent.get(appName);
+            if (startIntent != null) {
+                String packageName = startIntent.getComponent().getPackageName();
+                try {
+                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Error closing app", e);
+                }
+            }
+        }
+    }
+
+    private void sleep(int time) {
+        try {
+            Thread.sleep(time);
+        } catch (InterruptedException e) {
+            // ignore
+        }
+    }
+
+    private void reportError(String appName, String processName) {
+        ActivityManager am = (ActivityManager) getInstrumentation()
+                .getContext().getSystemService(Context.ACTIVITY_SERVICE);
+        List<ProcessErrorStateInfo> crashes = am.getProcessesInErrorState();
+        if (crashes != null) {
+            for (ProcessErrorStateInfo crash : crashes) {
+                if (!crash.processName.equals(processName))
+                    continue;
+
+                Log.w(TAG, appName + " crashed: " + crash.shortMsg);
+                mResult.putString(mNameToResultKey.get(appName), crash.shortMsg);
+                return;
+            }
+        }
+
+        mResult.putString(mNameToResultKey.get(appName),
+                "Crashed for unknown reason");
+        Log.w(TAG, appName
+                + " not found in process list, most likely it is crashed");
+    }
+
+    private class LaunchOrder {
+        private String mApp;
+        private String mCompilerFilter;
+        private String mLaunchReason;
+
+        LaunchOrder(String app, String compilerFilter, String launchReason){
+            mApp = app;
+            mCompilerFilter = compilerFilter;
+            mLaunchReason = launchReason;
+        }
+
+        public String getApp() {
+            return mApp;
+        }
+
+        public void setApp(String app) {
+            mApp = app;
+        }
+
+        public String getCompilerFilter() {
+            return mCompilerFilter;
+        }
+
+        public String getLaunchReason() {
+            return mLaunchReason;
+        }
+
+        public void setLaunchReason(String launchReason) {
+            mLaunchReason = launchReason;
+        }
+    }
+
+    private class AppLaunchResult {
+        long mLaunchTime;
+        long mCpuCycles;
+        long mMajorFaults;
+
+        AppLaunchResult() {
+            mLaunchTime = -1L;
+            mCpuCycles = -1L;
+            mMajorFaults = -1L;
+        }
+
+        AppLaunchResult(String launchTime, String cpuCycles, String majorFaults) {
+            try {
+                mLaunchTime = Long.parseLong(launchTime, 10);
+                mCpuCycles = Long.parseLong(cpuCycles, 10);
+                mMajorFaults = Long.parseLong(majorFaults, 10);
+            } catch (NumberFormatException e) {
+                Log.e(TAG, "Error parsing result", e);
+            }
+        }
+    }
+
+    private class AppLaunchRunnable implements Runnable {
+        private Intent mLaunchIntent;
+        private AppLaunchResult mLaunchResult;
+        private boolean mForceStopBeforeLaunch;
+        private String mLaunchReason;
+
+        public AppLaunchRunnable(Intent intent, boolean forceStopBeforeLaunch,
+                String launchReason) {
+            mLaunchIntent = intent;
+            mForceStopBeforeLaunch = forceStopBeforeLaunch;
+            mLaunchReason = launchReason;
+            mLaunchResult = new AppLaunchResult();
+        }
+
+        public AppLaunchResult getResult() {
+            return mLaunchResult;
+        }
+
+        public void run() {
+            File launchFile = null;
+            try {
+                String packageName = mLaunchIntent.getComponent().getPackageName();
+                String componentName = mLaunchIntent.getComponent().flattenToShortString();
+                if (mForceStopBeforeLaunch) {
+                    mAm.forceStopPackage(packageName, UserHandle.USER_CURRENT);
+                }
+                String launchCmd = String.format("%s %s", APP_LAUNCH_CMD, componentName);
+                if (mSimplePerfAppOnly) {
+                    try {
+                        // executeShellCommand cannot handle shell specific actions, like '&'.
+                        // Therefore, we create a file containing the command and make that
+                        // the command to launch.
+                        launchFile = File.createTempFile(LAUNCH_SCRIPT_NAME, ".sh");
+                        launchFile.setExecutable(true);
+                        try (FileOutputStream stream = new FileOutputStream(launchFile);
+                             BufferedWriter writer =
+                                new BufferedWriter(new OutputStreamWriter(stream))) {
+                            String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
+                            writer.write(cmd);
+                        }
+                        launchCmd = launchFile.getAbsolutePath();
+                    } catch (IOException e) {
+                        Log.w(TAG, "Error writing the launch command", e);
+                        return;
+                    }
+                } else if (null != mSimplePerfCmd) {
+                    launchCmd = String.format("%s %s", mSimplePerfCmd, launchCmd);
+                }
+                Log.v(TAG, "Final launch cmd:" + launchCmd);
+                ParcelFileDescriptor parcelDesc = getInstrumentation().getUiAutomation()
+                        .executeShellCommand(launchCmd);
+                mLaunchResult = parseLaunchTimeAndWrite(parcelDesc, String.format
+                        ("App Launch :%s %s", componentName, mLaunchReason));
+            } catch (RemoteException e) {
+                Log.w(TAG, "Error launching app", e);
+            } finally {
+                if (launchFile != null) {
+                    launchFile.delete();
+                }
+            }
+        }
+
+        /**
+         * Method to parse the launch time info and write the result to file
+         *
+         * @param parcelDesc
+         * @return
+         */
+        private AppLaunchResult parseLaunchTimeAndWrite(ParcelFileDescriptor parcelDesc,
+                String headerInfo) {
+            String launchTime = "-1";
+            String cpuCycles = "-1";
+            String majorFaults = "-1";
+            boolean launchSuccess = false;
+            try {
+                InputStream inputStream = new FileInputStream(parcelDesc.getFileDescriptor());
+                /* SAMPLE OUTPUT :
+                Starting: Intent { cmp=com.google.android.calculator/com.android.calculator2.Calculator }
+                Status: ok
+                Activity: com.google.android.calculator/com.android.calculator2.Calculator
+                ThisTime: 357
+                TotalTime: 357
+                WaitTime: 377
+                Complete*/
+                /* WITH SIMPLEPERF :
+                Performance counter statistics,
+                6595722690,cpu-cycles,4.511040,GHz,(100%),
+                0,major-faults,0.000,/sec,(100%),
+                Total test time,1.462129,seconds,*/
+                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(
+                        inputStream));
+                String line = null;
+                int lineCount = 1;
+                mBufferedWriter.newLine();
+                mBufferedWriter.write(headerInfo);
+                mBufferedWriter.newLine();
+                while ((line = bufferedReader.readLine()) != null) {
+                    if (lineCount == 2 && line.contains(SUCCESS_MESSAGE)) {
+                        launchSuccess = true;
+                    }
+                    // Parse TotalTime which is the launch time
+                    if (launchSuccess && lineCount == 5) {
+                        String launchSplit[] = line.split(":");
+                        launchTime = launchSplit[1].trim();
+                    }
+
+                    if (mSimplePerfAppOnly) {
+                        // Parse simpleperf output.
+                        if (lineCount == 9) {
+                            if (!line.contains("cpu-cycles")) {
+                                Log.e(TAG, "Error in simpleperf output");
+                            } else {
+                                cpuCycles = line.split(",")[0].trim();
+                            }
+                        } else if (lineCount == 10) {
+                            if (!line.contains("major-faults")) {
+                                Log.e(TAG, "Error in simpleperf output");
+                            } else {
+                                majorFaults = line.split(",")[0].trim();
+                            }
+                        }
+                    }
+                    mBufferedWriter.write(line);
+                    mBufferedWriter.newLine();
+                    lineCount++;
+                }
+                mBufferedWriter.flush();
+                inputStream.close();
+            } catch (IOException e) {
+                Log.w(TAG, "Error writing the launch file", e);
+            }
+            return new AppLaunchResult(launchTime, cpuCycles, majorFaults);
+        }
+
+    }
+}
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index bdbc149..a61ac54 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -15,6 +15,7 @@
 import android.os.Handler;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -986,11 +987,16 @@
                         legacyResults[i] = new RttResult();
                         legacyResults[i].status = result.getStatus();
                         legacyResults[i].bssid = result.getMacAddress().toString();
-                        legacyResults[i].distance = result.getDistanceMm() / 10;
-                        legacyResults[i].distanceStandardDeviation =
-                                result.getDistanceStdDevMm() / 10;
-                        legacyResults[i].rssi = result.getRssi();
-                        legacyResults[i].ts = result.getRangingTimestampUs();
+                        if (result.getStatus() == RangingResult.STATUS_SUCCESS) {
+                            legacyResults[i].distance = result.getDistanceMm() / 10;
+                            legacyResults[i].distanceStandardDeviation =
+                                    result.getDistanceStdDevMm() / 10;
+                            legacyResults[i].rssi = result.getRssi();
+                            legacyResults[i].ts = result.getRangingTimestampUs();
+                        } else {
+                            // just in case legacy API needed some relatively real timestamp
+                            legacyResults[i].ts = SystemClock.elapsedRealtime() * 1000;
+                        }
                     }
                     listener.onSuccess(legacyResults);
                 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 897b1ea..d2cdf8d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -99,35 +99,45 @@
     // Supplicant error codes:
     /**
      * The error code if there was a problem authenticating.
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
     public static final int ERROR_AUTHENTICATING = 1;
 
     /**
      * The reason code if there is no error during authentication.
      * It could also imply that there no authentication in progress,
      * this reason code also serves as a reset value.
+     * @deprecated This is no longer supported.
      * @hide
      */
+    @Deprecated
     public static final int ERROR_AUTH_FAILURE_NONE = 0;
 
     /**
      * The reason code if there was a timeout authenticating.
+     * @deprecated This is no longer supported.
      * @hide
      */
+    @Deprecated
     public static final int ERROR_AUTH_FAILURE_TIMEOUT = 1;
 
     /**
      * The reason code if there was a wrong password while
      * authenticating.
+     * @deprecated This is no longer supported.
      * @hide
      */
+    @Deprecated
     public static final int ERROR_AUTH_FAILURE_WRONG_PSWD = 2;
 
     /**
      * The reason code if there was EAP failure while
      * authenticating.
+     * @deprecated This is no longer supported.
      * @hide
      */
+    @Deprecated
     public static final int ERROR_AUTH_FAILURE_EAP_FAILURE = 3;
 
     /**
@@ -565,8 +575,10 @@
      * to perform Wi-Fi operations) or the connection to the supplicant has been
      * lost. One extra provides the connection state as a boolean, where {@code true}
      * means CONNECTED.
+     * @deprecated This is no longer supported.
      * @see #EXTRA_SUPPLICANT_CONNECTED
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String SUPPLICANT_CONNECTION_CHANGE_ACTION =
         "android.net.wifi.supplicant.CONNECTION_CHANGE";
@@ -575,7 +587,9 @@
      * the supplicant daemon has been gained or lost. {@code true} means
      * a connection now exists.
      * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}.
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
     public static final String EXTRA_SUPPLICANT_CONNECTED = "connected";
     /**
      * Broadcast intent action indicating that the state of Wi-Fi connectivity
@@ -612,7 +626,9 @@
      * the overall state of connectivity.
      * @see #EXTRA_NEW_STATE
      * @see #EXTRA_SUPPLICANT_ERROR
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String SUPPLICANT_STATE_CHANGED_ACTION =
         "android.net.wifi.supplicant.STATE_CHANGE";
@@ -620,7 +636,9 @@
      * The lookup key for a {@link SupplicantState} describing the new state
      * Retrieve with
      * {@link android.content.Intent#getParcelableExtra(String)}.
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
     public static final String EXTRA_NEW_STATE = "newState";
 
     /**
@@ -629,7 +647,9 @@
      * Retrieve with
      * {@link android.content.Intent#getIntExtra(String, int)}.
      * @see #ERROR_AUTHENTICATING
+     * @deprecated This is no longer supported.
      */
+    @Deprecated
     public static final String EXTRA_SUPPLICANT_ERROR = "supplicantError";
 
     /**
@@ -638,8 +658,10 @@
      * Retrieve with
      * {@link android.content.Intent#getIntExtra(String, int)}.
      * @see #ERROR_AUTH_FAILURE_#REASON_CODE
+     * @deprecated This is no longer supported.
      * @hide
      */
+    @Deprecated
     public static final String EXTRA_SUPPLICANT_ERROR_REASON = "supplicantErrorReason";
 
     /**
@@ -3617,8 +3639,10 @@
      * Restore state from the older version of back up data.
      * The old backup data was essentially a backup of wpa_supplicant.conf
      * and ipconfig.txt file.
+     * @deprecated this is no longer supported.
      * @hide
      */
+    @Deprecated
     public void restoreSupplicantBackupData(byte[] supplicantData, byte[] ipConfigData) {
         try {
             mService.restoreSupplicantBackupData(supplicantData, ipConfigData);
diff --git a/wifi/java/android/net/wifi/WpsInfo.java b/wifi/java/android/net/wifi/WpsInfo.java
index ae2e771..d12cce1 100644
--- a/wifi/java/android/net/wifi/WpsInfo.java
+++ b/wifi/java/android/net/wifi/WpsInfo.java
@@ -21,37 +21,58 @@
 
 /**
  * A class representing Wi-Fi Protected Setup
- *
+ * @deprecated This class is no longer supported.
  * {@see WifiP2pConfig}
  */
+@Deprecated
 public class WpsInfo implements Parcelable {
 
-    /** Push button configuration */
+    /** Push button configuration
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public static final int PBC     = 0;
-    /** Display pin method configuration - pin is generated and displayed on device */
+    /** Display pin method configuration - pin is generated and displayed on device
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public static final int DISPLAY = 1;
-    /** Keypad pin method configuration - pin is entered on device */
+    /** Keypad pin method configuration - pin is entered on device
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public static final int KEYPAD  = 2;
-    /** Label pin method configuration - pin is labelled on device */
+    /** Label pin method configuration - pin is labelled on device
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public static final int LABEL   = 3;
-    /** Invalid configuration */
+    /** Invalid configuration
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public static final int INVALID = 4;
 
-    /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details */
+    /** Wi-Fi Protected Setup. www.wi-fi.org/wifi-protected-setup has details
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public int setup;
 
-    /** Passed with pin method KEYPAD */
+    /** Passed with pin method KEYPAD
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public String BSSID;
 
-    /** Passed with pin method configuration */
+    /** Passed with pin method configuration
+     * @deprecated This is no longer supported.*/
+    @Deprecated
     public String pin;
 
+    /** @deprecated This API is no longer supported.*/
+    @Deprecated
     public WpsInfo() {
         setup = INVALID;
         BSSID = null;
         pin = null;
     }
 
+    /** @deprecated This API is no longer supported.*/
+    @Deprecated
     public String toString() {
         StringBuffer sbuf = new StringBuffer();
         sbuf.append(" setup: ").append(setup);
@@ -63,12 +84,16 @@
         return sbuf.toString();
     }
 
-    /** Implement the Parcelable interface */
+    /** Implement the Parcelable interface
+     * @deprecated This API is no longer supported.*/
+    @Deprecated
     public int describeContents() {
         return 0;
     }
 
-    /* Copy constructor */
+    /* Copy constructor
+    * @deprecated This API is no longer supported.*/
+    @Deprecated
     public WpsInfo(WpsInfo source) {
         if (source != null) {
             setup = source.setup;
@@ -77,16 +102,22 @@
         }
     }
 
-    /** Implement the Parcelable interface */
+    /** Implement the Parcelable interface
+     * @deprecated This API is no longer supported. */
+    @Deprecated
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeInt(setup);
         dest.writeString(BSSID);
         dest.writeString(pin);
     }
 
-    /** Implement the Parcelable interface */
+    /** Implement the Parcelable interface
+     * @deprecated This API is no longer supported.*/
+    @Deprecated
     public static final Creator<WpsInfo> CREATOR =
         new Creator<WpsInfo>() {
+            /** @deprecated This API is nolonger supported.*/
+            @Deprecated
             public WpsInfo createFromParcel(Parcel in) {
                 WpsInfo config = new WpsInfo();
                 config.setup = in.readInt();
@@ -95,6 +126,8 @@
                 return config;
             }
 
+            /** @deprecated This API is nolonger supported.*/
+            @Deprecated
             public WpsInfo[] newArray(int size) {
                 return new WpsInfo[size];
             }