Merge "Update rotate navbar icon to Google Material spec" into pi-dev
diff --git a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
index dccb34b..fefda64 100644
--- a/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
+++ b/apct-tests/perftests/core/src/android/text/TextPerfUtils.java
@@ -76,7 +76,7 @@
         }
 
         SpannableStringBuilder ssb = new SpannableStringBuilder(cs);
-        for (int i = 0; i < ssb.length(); i += wordLen) {
+        for (int i = 0; i < ssb.length(); i += wordLen + 1) {
             final int spanStart = i;
             final int spanEnd = (i + wordLen) > ssb.length() ? ssb.length() : i + wordLen;
 
diff --git a/api/current.txt b/api/current.txt
index f92896d..59e7c46 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5196,6 +5196,7 @@
     field public static final java.lang.String CATEGORY_ERROR = "err";
     field public static final java.lang.String CATEGORY_EVENT = "event";
     field public static final java.lang.String CATEGORY_MESSAGE = "msg";
+    field public static final java.lang.String CATEGORY_NAVIGATION = "navigation";
     field public static final java.lang.String CATEGORY_PROGRESS = "progress";
     field public static final java.lang.String CATEGORY_PROMO = "promo";
     field public static final java.lang.String CATEGORY_RECOMMENDATION = "recommendation";
@@ -6330,6 +6331,7 @@
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager) throws android.content.res.Resources.NotFoundException;
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
+    method public boolean supportsTransferOwnership();
     method public boolean usesPolicy(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.admin.DeviceAdminInfo> CREATOR;
@@ -6394,7 +6396,6 @@
     field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING";
     field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
     field public static final java.lang.String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
-    field public static final java.lang.String SUPPORT_TRANSFER_OWNERSHIP_META_DATA = "android.app.support_transfer_ownership";
   }
 
   public class DeviceAdminService extends android.app.Service {
@@ -7419,12 +7420,14 @@
     method public int getEventType();
     method public java.lang.String getPackageName();
     method public java.lang.String getShortcutId();
+    method public int getStandbyBucket();
     method public long getTimeStamp();
     field public static final int CONFIGURATION_CHANGE = 5; // 0x5
     field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
     field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
     field public static final int NONE = 0; // 0x0
     field public static final int SHORTCUT_INVOCATION = 8; // 0x8
+    field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
     field public static final int USER_INTERACTION = 7; // 0x7
   }
 
@@ -21246,9 +21249,10 @@
     method public final boolean switchToPreviousInputMethod();
     method public void updateFullscreenMode();
     method public void updateInputViewShown();
+    field public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3; // 0x3
     field public static final int BACK_DISPOSITION_DEFAULT = 0; // 0x0
-    field public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
-    field public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
+    field public static final deprecated int BACK_DISPOSITION_WILL_DISMISS = 2; // 0x2
+    field public static final deprecated int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // 0x1
   }
 
   public class InputMethodService.InputMethodImpl extends android.inputmethodservice.AbstractInputMethodService.AbstractInputMethodImpl {
@@ -28678,7 +28682,7 @@
     field public static final int IEEE8021X = 3; // 0x3
     field public static final int NONE = 0; // 0x0
     field public static final int WPA_EAP = 2; // 0x2
-    field public static final deprecated int WPA_PSK = 1; // 0x1
+    field public static final int WPA_PSK = 1; // 0x1
     field public static final java.lang.String[] strings;
     field public static final java.lang.String varName = "key_mgmt";
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 5ec84fe..af783ca 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -336,6 +336,9 @@
   }
 
   public class Notification implements android.os.Parcelable {
+    field public static final java.lang.String CATEGORY_CAR_EMERGENCY = "car_emergency";
+    field public static final java.lang.String CATEGORY_CAR_INFORMATION = "car_information";
+    field public static final java.lang.String CATEGORY_CAR_WARNING = "car_warning";
     field public static final java.lang.String EXTRA_ALLOW_DURING_SETUP = "android.allowDuringSetup";
     field public static final java.lang.String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
     field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400
@@ -719,10 +722,8 @@
 
   public static final class UsageEvents.Event {
     method public java.lang.String getNotificationChannelId();
-    method public int getStandbyBucket();
     field public static final int NOTIFICATION_INTERRUPTION = 12; // 0xc
     field public static final int NOTIFICATION_SEEN = 10; // 0xa
-    field public static final int STANDBY_BUCKET_CHANGED = 11; // 0xb
   }
 
   public final class UsageStatsManager {
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 3570144..2b85ec0 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -34,11 +34,11 @@
 
 FdBuffer::~FdBuffer() {}
 
-status_t FdBuffer::read(int fd, int64_t timeout) {
-    struct pollfd pfds = {.fd = fd, .events = POLLIN};
+status_t FdBuffer::read(unique_fd* fd, int64_t timeout) {
+    struct pollfd pfds = {.fd = fd->get(), .events = POLLIN};
     mStartTime = uptimeMillis();
 
-    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+    fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK);
 
     while (true) {
         if (mBuffer.size() >= MAX_BUFFER_COUNT * BUFFER_SIZE) {
@@ -67,16 +67,16 @@
                 VLOG("return event has error %s", strerror(errno));
                 return errno != 0 ? -errno : UNKNOWN_ERROR;
             } else {
-                ssize_t amt = ::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
+                ssize_t amt = ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite());
                 if (amt < 0) {
                     if (errno == EAGAIN || errno == EWOULDBLOCK) {
                         continue;
                     } else {
-                        VLOG("Fail to read %d: %s", fd, strerror(errno));
+                        VLOG("Fail to read %d: %s", fd->get(), strerror(errno));
                         return -errno;
                     }
                 } else if (amt == 0) {
-                    VLOG("Reached EOF of fd=%d", fd);
+                    VLOG("Reached EOF of fd=%d", fd->get());
                     break;
                 }
                 mBuffer.wp()->move(amt);
@@ -87,7 +87,7 @@
     return NO_ERROR;
 }
 
-status_t FdBuffer::readFully(int fd) {
+status_t FdBuffer::readFully(unique_fd* fd) {
     mStartTime = uptimeMillis();
 
     while (true) {
@@ -99,10 +99,10 @@
         }
         if (mBuffer.writeBuffer() == NULL) return NO_MEMORY;
 
-        ssize_t amt =
-                TEMP_FAILURE_RETRY(::read(fd, mBuffer.writeBuffer(), mBuffer.currentToWrite()));
+        ssize_t amt = TEMP_FAILURE_RETRY(
+                ::read(fd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite()));
         if (amt < 0) {
-            VLOG("Fail to read %d: %s", fd, strerror(errno));
+            VLOG("Fail to read %d: %s", fd->get(), strerror(errno));
             return -errno;
         } else if (amt == 0) {
             VLOG("Done reading %zu bytes", mBuffer.size());
@@ -116,20 +116,20 @@
     return NO_ERROR;
 }
 
-status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64_t timeoutMs,
-                                             const bool isSysfs) {
+status_t FdBuffer::readProcessedDataInStream(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd,
+                                             int64_t timeoutMs, const bool isSysfs) {
     struct pollfd pfds[] = {
-            {.fd = fd, .events = POLLIN},
-            {.fd = toFd, .events = POLLOUT},
-            {.fd = fromFd, .events = POLLIN},
+            {.fd = fd->get(), .events = POLLIN},
+            {.fd = toFd->get(), .events = POLLOUT},
+            {.fd = fromFd->get(), .events = POLLIN},
     };
 
     mStartTime = uptimeMillis();
 
     // mark all fds non blocking
-    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
-    fcntl(toFd, F_SETFL, fcntl(toFd, F_GETFL, 0) | O_NONBLOCK);
-    fcntl(fromFd, F_SETFL, fcntl(fromFd, F_GETFL, 0) | O_NONBLOCK);
+    fcntl(fd->get(), F_SETFL, fcntl(fd->get(), F_GETFL, 0) | O_NONBLOCK);
+    fcntl(toFd->get(), F_SETFL, fcntl(toFd->get(), F_GETFL, 0) | O_NONBLOCK);
+    fcntl(fromFd->get(), F_SETFL, fcntl(fromFd->get(), F_GETFL, 0) | O_NONBLOCK);
 
     // A circular buffer holds data read from fd and writes to parsing process
     uint8_t cirBuf[BUFFER_SIZE];
@@ -166,10 +166,10 @@
         for (int i = 0; i < 3; ++i) {
             if ((pfds[i].revents & POLLERR) != 0) {
                 if (i == 0 && isSysfs) {
-                    VLOG("fd %d is sysfs, ignore its POLLERR return value", fd);
+                    VLOG("fd %d is sysfs, ignore its POLLERR return value", fd->get());
                     continue;
                 }
-                VLOG("fd[%d]=%d returns error events: %s", i, fd, strerror(errno));
+                VLOG("fd[%d]=%d returns error events: %s", i, fd->get(), strerror(errno));
                 return errno != 0 ? -errno : UNKNOWN_ERROR;
             }
         }
@@ -178,17 +178,17 @@
         if (cirSize != BUFFER_SIZE && pfds[0].fd != -1) {
             ssize_t amt;
             if (rpos >= wpos) {
-                amt = ::read(fd, cirBuf + rpos, BUFFER_SIZE - rpos);
+                amt = ::read(fd->get(), cirBuf + rpos, BUFFER_SIZE - rpos);
             } else {
-                amt = ::read(fd, cirBuf + rpos, wpos - rpos);
+                amt = ::read(fd->get(), cirBuf + rpos, wpos - rpos);
             }
             if (amt < 0) {
                 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
-                    VLOG("Fail to read fd %d: %s", fd, strerror(errno));
+                    VLOG("Fail to read fd %d: %s", fd->get(), strerror(errno));
                     return -errno;
                 }  // otherwise just continue
             } else if (amt == 0) {
-                VLOG("Reached EOF of input file %d", fd);
+                VLOG("Reached EOF of input file %d", fd->get());
                 pfds[0].fd = -1;  // reach EOF so don't have to poll pfds[0].
             } else {
                 rpos += amt;
@@ -200,13 +200,13 @@
         if (cirSize > 0 && pfds[1].fd != -1) {
             ssize_t amt;
             if (rpos > wpos) {
-                amt = ::write(toFd, cirBuf + wpos, rpos - wpos);
+                amt = ::write(toFd->get(), cirBuf + wpos, rpos - wpos);
             } else {
-                amt = ::write(toFd, cirBuf + wpos, BUFFER_SIZE - wpos);
+                amt = ::write(toFd->get(), cirBuf + wpos, BUFFER_SIZE - wpos);
             }
             if (amt < 0) {
                 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
-                    VLOG("Fail to write toFd %d: %s", toFd, strerror(errno));
+                    VLOG("Fail to write toFd %d: %s", toFd->get(), strerror(errno));
                     return -errno;
                 }  // otherwise just continue
             } else {
@@ -217,8 +217,8 @@
 
         // if buffer is empty and fd is closed, close write fd.
         if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) {
-            VLOG("Close write pipe %d", toFd);
-            ::close(pfds[1].fd);
+            VLOG("Close write pipe %d", toFd->get());
+            toFd->reset();
             pfds[1].fd = -1;
         }
 
@@ -231,14 +231,14 @@
         }
 
         // read from parsing process
-        ssize_t amt = ::read(fromFd, mBuffer.writeBuffer(), mBuffer.currentToWrite());
+        ssize_t amt = ::read(fromFd->get(), mBuffer.writeBuffer(), mBuffer.currentToWrite());
         if (amt < 0) {
             if (!(errno == EAGAIN || errno == EWOULDBLOCK)) {
-                VLOG("Fail to read fromFd %d: %s", fromFd, strerror(errno));
+                VLOG("Fail to read fromFd %d: %s", fromFd->get(), strerror(errno));
                 return -errno;
             }  // otherwise just continue
         } else if (amt == 0) {
-            VLOG("Reached EOF of fromFd %d", fromFd);
+            VLOG("Reached EOF of fromFd %d", fromFd->get());
             break;
         } else {
             mBuffer.wp()->move(amt);
diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h
index 34ebcf5..db3a74b 100644
--- a/cmds/incidentd/src/FdBuffer.h
+++ b/cmds/incidentd/src/FdBuffer.h
@@ -18,10 +18,12 @@
 #ifndef FD_BUFFER_H
 #define FD_BUFFER_H
 
+#include <android-base/unique_fd.h>
 #include <android/util/EncodedBuffer.h>
 #include <utils/Errors.h>
 
 using namespace android;
+using namespace android::base;
 using namespace android::util;
 using namespace std;
 
@@ -38,13 +40,13 @@
      * Returns NO_ERROR if there were no errors or if we timed out.
      * Will mark the file O_NONBLOCK.
      */
-    status_t read(int fd, int64_t timeoutMs);
+    status_t read(unique_fd* fd, int64_t timeoutMs);
 
     /**
      * Read the data until we hit eof.
      * Returns NO_ERROR if there were no errors.
      */
-    status_t readFully(int fd);
+    status_t readFully(unique_fd* fd);
 
     /**
      * Read processed results by streaming data to a parsing process, e.g. incident helper.
@@ -56,8 +58,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(unique_fd* fd, unique_fd* toFd, unique_fd* fromFd,
+                                       int64_t timeoutMs, const bool isSysfs = false);
 
     /**
      * Whether we timed out.
diff --git a/cmds/incidentd/src/IncidentService.cpp b/cmds/incidentd/src/IncidentService.cpp
index d02b4dd..aeccefd 100644
--- a/cmds/incidentd/src/IncidentService.cpp
+++ b/cmds/incidentd/src/IncidentService.cpp
@@ -352,7 +352,8 @@
             printPrivacy(p, out, String8(""));
         } else if (opt == "parse") {
             FdBuffer buf;
-            status_t error = buf.read(fileno(in), 60000);
+            unique_fd infd(fileno(in));
+            status_t error = buf.read(&infd, 60000);
             if (error != NO_ERROR) {
                 fprintf(err, "Error reading from stdin\n");
                 return error;
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 5cde5a9..ab4e764 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -277,8 +277,8 @@
 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) {
+    unique_fd fd(open(mFilename, O_RDONLY | O_CLOEXEC));
+    if (fd.get() == -1) {
         ALOGW("FileSection '%s' failed to open file", this->name.string());
         return -errno;
     }
@@ -299,9 +299,8 @@
     }
 
     // parent process
-    status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(),
-                                                           this->timeoutMs, mIsSysfs);
-    close(fd);  // close the fd anyway.
+    status_t readStatus = buffer.readProcessedDataInStream(
+            &fd, &p2cPipe.writeFd(), &c2pPipe.readFd(), this->timeoutMs, mIsSysfs);
 
     if (readStatus != NO_ERROR || buffer.timedOut()) {
         ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s",
@@ -342,17 +341,17 @@
 status_t GZipSection::Execute(ReportRequestSet* requests) const {
     // Reads the files in order, use the first available one.
     int index = 0;
-    int fd = -1;
+    unique_fd fd;
     while (mFilenames[index] != NULL) {
-        fd = open(mFilenames[index], O_RDONLY | O_CLOEXEC);
-        if (fd != -1) {
+        fd.reset(open(mFilenames[index], O_RDONLY | O_CLOEXEC));
+        if (fd.get() != -1) {
             break;
         }
         ALOGW("GZipSection failed to open file %s", mFilenames[index]);
         index++;  // look at the next file.
     }
-    VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd);
-    if (fd == -1) return -1;
+    VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd.get());
+    if (fd.get() == -1) return -1;
 
     FdBuffer buffer;
     Fpipe p2cPipe;
@@ -388,9 +387,9 @@
     VLOG("GZipSection '%s' editPos=%zd, dataBeginAt=%zd", this->name.string(), editPos,
          dataBeginAt);
 
-    status_t readStatus = buffer.readProcessedDataInStream(
-            fd, p2cPipe.writeFd(), c2pPipe.readFd(), this->timeoutMs, isSysfs(mFilenames[index]));
-    close(fd);  // close the fd anyway.
+    status_t readStatus =
+            buffer.readProcessedDataInStream(&fd, &p2cPipe.writeFd(), &c2pPipe.readFd(),
+                                             this->timeoutMs, isSysfs(mFilenames[index]));
 
     if (readStatus != NO_ERROR || buffer.timedOut()) {
         ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s",
@@ -424,7 +423,7 @@
 // ================================================================================
 struct WorkerThreadData : public virtual RefBase {
     const WorkerThreadSection* section;
-    int fds[2];
+    Fpipe pipe;
 
     // Lock protects these fields
     mutex lock;
@@ -433,16 +432,10 @@
 
     WorkerThreadData(const WorkerThreadSection* section);
     virtual ~WorkerThreadData();
-
-    int readFd() { return fds[0]; }
-    int writeFd() { return fds[1]; }
 };
 
 WorkerThreadData::WorkerThreadData(const WorkerThreadSection* sec)
-    : section(sec), workerDone(false), workerError(NO_ERROR) {
-    fds[0] = -1;
-    fds[1] = -1;
-}
+    : section(sec), workerDone(false), workerError(NO_ERROR) {}
 
 WorkerThreadData::~WorkerThreadData() {}
 
@@ -454,7 +447,7 @@
 
 static void* worker_thread_func(void* cookie) {
     WorkerThreadData* data = (WorkerThreadData*)cookie;
-    status_t err = data->section->BlockingCall(data->writeFd());
+    status_t err = data->section->BlockingCall(data->pipe.writeFd().get());
 
     {
         unique_lock<mutex> lock(data->lock);
@@ -462,7 +455,7 @@
         data->workerError = err;
     }
 
-    close(data->writeFd());
+    data->pipe.writeFd().reset();
     data->decStrong(data->section);
     // data might be gone now. don't use it after this point in this thread.
     return NULL;
@@ -479,8 +472,7 @@
     sp<WorkerThreadData> data = new WorkerThreadData(this);
 
     // Create the pipe
-    err = pipe(data->fds);
-    if (err != 0) {
+    if (!data->pipe.init()) {
         return -errno;
     }
 
@@ -507,7 +499,7 @@
     pthread_attr_destroy(&attr);
 
     // Loop reading until either the timeout or the worker side is done (i.e. eof).
-    err = buffer.read(data->readFd(), this->timeoutMs);
+    err = buffer.read(&data->pipe.readFd(), this->timeoutMs);
     if (err != NO_ERROR) {
         // TODO: Log this error into the incident report.
         ALOGW("WorkerThreadSection '%s' reader failed with error '%s'", this->name.string(),
@@ -516,7 +508,7 @@
 
     // Done with the read fd. The worker thread closes the write one so
     // we never race and get here first.
-    close(data->readFd());
+    data->pipe.readFd().reset();
 
     // If the worker side is finished, then return its error (which may overwrite
     // our possible error -- but it's more interesting anyway).  If not, then we timed out.
@@ -602,7 +594,8 @@
     // child process to execute the command as root
     if (cmdPid == 0) {
         // replace command's stdout with ihPipe's write Fd
-        if (dup2(cmdPipe.writeFd(), STDOUT_FILENO) != 1 || !ihPipe.close() || !cmdPipe.close()) {
+        if (dup2(cmdPipe.writeFd().get(), STDOUT_FILENO) != 1 || !ihPipe.close() ||
+            !cmdPipe.close()) {
             ALOGW("CommandSection '%s' failed to set up stdout: %s", this->name.string(),
                   strerror(errno));
             _exit(EXIT_FAILURE);
@@ -619,8 +612,8 @@
         return -errno;
     }
 
-    close(cmdPipe.writeFd());
-    status_t readStatus = buffer.read(ihPipe.readFd(), this->timeoutMs);
+    cmdPipe.writeFd().reset();
+    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");
@@ -921,10 +914,10 @@
             break;
         } else if (child == 0) {
             // This is the child process.
-            close(dumpPipe.readFd());
+            dumpPipe.readFd().reset();
             const int ret = dump_backtrace_to_file_timeout(
                     pid, is_java_process ? kDebuggerdJavaBacktrace : kDebuggerdNativeBacktrace,
-                    is_java_process ? 5 : 20, dumpPipe.writeFd());
+                    is_java_process ? 5 : 20, dumpPipe.writeFd().get());
             if (ret == -1) {
                 if (errno == 0) {
                     ALOGW("Dumping failed for pid '%d', likely due to a timeout\n", pid);
@@ -932,25 +925,17 @@
                     ALOGE("Dumping failed for pid '%d': %s\n", pid, strerror(errno));
                 }
             }
-            if (close(dumpPipe.writeFd()) != 0) {
-                ALOGW("TombstoneSection '%s' failed to close dump pipe writeFd: %d",
-                      this->name.string(), errno);
-                _exit(EXIT_FAILURE);
-            }
-
+            dumpPipe.writeFd().reset();
             _exit(EXIT_SUCCESS);
         }
-        close(dumpPipe.writeFd());
+        dumpPipe.writeFd().reset();
         // Parent process.
         // Read from the pipe concurrently to avoid blocking the child.
         FdBuffer buffer;
-        err = buffer.readFully(dumpPipe.readFd());
+        err = buffer.readFully(&dumpPipe.readFd());
         if (err != NO_ERROR) {
             ALOGW("TombstoneSection '%s' failed to read stack dump: %d", this->name.string(), err);
-            if (close(dumpPipe.readFd()) != 0) {
-                ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %s",
-                      this->name.string(), strerror(errno));
-            }
+            dumpPipe.readFd().reset();
             break;
         }
 
@@ -967,13 +952,7 @@
         proto.write(android::os::BackTraceProto::Stack::DUMP_DURATION_NS,
                     static_cast<long long>(Nanotime() - start));
         proto.end(token);
-
-        if (close(dumpPipe.readFd()) != 0) {
-            ALOGW("TombstoneSection '%s' failed to close dump pipe readFd: %d", this->name.string(),
-                  errno);
-            err = -errno;
-            break;
-        }
+        dumpPipe.readFd().reset();
     }
 
     proto.flush(pipeWriteFd);
diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp
index c869c7a..d799513 100644
--- a/cmds/incidentd/src/incidentd_util.cpp
+++ b/cmds/incidentd/src/incidentd_util.cpp
@@ -53,16 +53,17 @@
 
 bool Fpipe::init() { return Pipe(&mRead, &mWrite); }
 
-int Fpipe::readFd() const { return mRead.get(); }
+unique_fd& Fpipe::readFd() { return mRead; }
 
-int Fpipe::writeFd() const { return mWrite.get(); }
+unique_fd& Fpipe::writeFd() { return mWrite; }
 
 pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output) {
     // fork used in multithreaded environment, avoid adding unnecessary code in child process
     pid_t pid = fork();
     if (pid == 0) {
-        if (TEMP_FAILURE_RETRY(dup2(input->readFd(), STDIN_FILENO)) < 0 || !input->close() ||
-            TEMP_FAILURE_RETRY(dup2(output->writeFd(), STDOUT_FILENO)) < 0 || !output->close()) {
+        if (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 || !input->close() ||
+            TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 ||
+            !output->close()) {
             ALOGW("Can't setup stdin and stdout for command %s", cmd);
             _exit(EXIT_FAILURE);
         }
@@ -76,8 +77,8 @@
         _exit(EXIT_FAILURE);  // always exits with failure if any
     }
     // close the fds used in child process.
-    close(input->readFd());
-    close(output->writeFd());
+    input->readFd().reset();
+    output->writeFd().reset();
     return pid;
 }
 
diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h
index 3f7df91..228d776 100644
--- a/cmds/incidentd/src/incidentd_util.h
+++ b/cmds/incidentd/src/incidentd_util.h
@@ -41,8 +41,8 @@
 
     bool init();
     bool close();
-    int readFd() const;
-    int writeFd() const;
+    unique_fd& readFd();
+    unique_fd& writeFd();
 
 private:
     unique_fd mRead;
diff --git a/cmds/incidentd/tests/FdBuffer_test.cpp b/cmds/incidentd/tests/FdBuffer_test.cpp
index 0e5eec6..bf77017 100644
--- a/cmds/incidentd/tests/FdBuffer_test.cpp
+++ b/cmds/incidentd/tests/FdBuffer_test.cpp
@@ -37,6 +37,7 @@
 public:
     virtual void SetUp() override {
         ASSERT_NE(tf.fd, -1);
+        tffd.reset(tf.fd);
         ASSERT_NE(p2cPipe.init(), -1);
         ASSERT_NE(c2pPipe.init(), -1);
     }
@@ -56,13 +57,13 @@
         EXPECT_EQ(expected[i], '\0');
     }
 
-    bool DoDataStream(int rFd, int wFd) {
+    bool DoDataStream(unique_fd* rFd, unique_fd* wFd) {
         char buf[BUFFER_SIZE];
         ssize_t nRead;
-        while ((nRead = read(rFd, buf, BUFFER_SIZE)) > 0) {
+        while ((nRead = read(rFd->get(), buf, BUFFER_SIZE)) > 0) {
             ssize_t nWritten = 0;
             while (nWritten < nRead) {
-                ssize_t amt = write(wFd, buf + nWritten, nRead - nWritten);
+                ssize_t amt = write(wFd->get(), buf + nWritten, nRead - nWritten);
                 if (amt < 0) {
                     return false;
                 }
@@ -75,6 +76,7 @@
 protected:
     FdBuffer buffer;
     TemporaryFile tf;
+    unique_fd tffd;
     Fpipe p2cPipe;
     Fpipe c2pPipe;
 
@@ -85,7 +87,7 @@
 TEST_F(FdBufferTest, ReadAndWrite) {
     std::string testdata = "FdBuffer test string";
     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
-    ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
+    ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT));
     AssertBufferReadSuccessful(testdata.size());
     AssertBufferContent(testdata.c_str());
 }
@@ -98,7 +100,7 @@
 TEST_F(FdBufferTest, ReadAndIterate) {
     std::string testdata = "FdBuffer test string";
     ASSERT_TRUE(WriteStringToFile(testdata, tf.path));
-    ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, READ_TIMEOUT));
+    ASSERT_EQ(NO_ERROR, buffer.read(&tffd, READ_TIMEOUT));
 
     int i = 0;
     EncodedBuffer::iterator it = buffer.data();
@@ -117,16 +119,16 @@
     ASSERT_TRUE(pid != -1);
 
     if (pid == 0) {
-        close(c2pPipe.readFd());
+        c2pPipe.readFd().reset();
         while (true) {
             write(c2pPipe.writeFd(), "poo", 3);
             sleep(1);
         }
         _exit(EXIT_FAILURE);
     } else {
-        close(c2pPipe.writeFd());
+        c2pPipe.writeFd().reset();
 
-        status_t status = buffer.read(c2pPipe.readFd(), QUICK_TIMEOUT_MS);
+        status_t status = buffer.read(&c2pPipe.readFd(), QUICK_TIMEOUT_MS);
         ASSERT_EQ(NO_ERROR, status);
         EXPECT_TRUE(buffer.timedOut());
 
@@ -143,20 +145,20 @@
     ASSERT_TRUE(pid != -1);
 
     if (pid == 0) {
-        close(p2cPipe.writeFd());
-        close(c2pPipe.readFd());
+        p2cPipe.writeFd().reset();
+        c2pPipe.readFd().reset();
         ASSERT_TRUE(WriteStringToFd(HEAD, c2pPipe.writeFd()));
-        ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
         // Must exit here otherwise the child process will continue executing the test binary.
         _exit(EXIT_SUCCESS);
     } else {
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
-                                                             c2pPipe.readFd(), READ_TIMEOUT));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+                                                             &c2pPipe.readFd(), READ_TIMEOUT));
         AssertBufferReadSuccessful(HEAD.size() + testdata.size());
         AssertBufferContent(expected.c_str());
         wait(&pid);
@@ -172,23 +174,23 @@
     ASSERT_TRUE(pid != -1);
 
     if (pid == 0) {
-        close(p2cPipe.writeFd());
-        close(c2pPipe.readFd());
+        p2cPipe.writeFd().reset();
+        c2pPipe.readFd().reset();
         std::string data;
         // wait for read finishes then write.
         ASSERT_TRUE(ReadFdToString(p2cPipe.readFd(), &data));
         data = HEAD + data;
         ASSERT_TRUE(WriteStringToFd(data, c2pPipe.writeFd()));
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
         // Must exit here otherwise the child process will continue executing the test binary.
         _exit(EXIT_SUCCESS);
     } else {
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
-                                                             c2pPipe.readFd(), READ_TIMEOUT));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+                                                             &c2pPipe.readFd(), READ_TIMEOUT));
         AssertBufferReadSuccessful(HEAD.size() + testdata.size());
         AssertBufferContent(expected.c_str());
         wait(&pid);
@@ -202,18 +204,18 @@
     ASSERT_TRUE(pid != -1);
 
     if (pid == 0) {
-        close(p2cPipe.writeFd());
-        close(c2pPipe.readFd());
-        ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.writeFd().reset();
+        c2pPipe.readFd().reset();
+        ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
         _exit(EXIT_SUCCESS);
     } else {
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
-                                                             c2pPipe.readFd(), READ_TIMEOUT));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+                                                             &c2pPipe.readFd(), READ_TIMEOUT));
         AssertBufferReadSuccessful(0);
         AssertBufferContent("");
         wait(&pid);
@@ -223,24 +225,24 @@
 TEST_F(FdBufferTest, ReadInStreamMoreThan4MB) {
     const std::string testFile = kTestDataPath + "morethan4MB.txt";
     size_t fourMB = (size_t)4 * 1024 * 1024;
-    int fd = open(testFile.c_str(), O_RDONLY | O_CLOEXEC);
-    ASSERT_NE(fd, -1);
+    unique_fd fd(open(testFile.c_str(), O_RDONLY | O_CLOEXEC));
+    ASSERT_NE(fd.get(), -1);
     int pid = fork();
     ASSERT_TRUE(pid != -1);
 
     if (pid == 0) {
-        close(p2cPipe.writeFd());
-        close(c2pPipe.readFd());
-        ASSERT_TRUE(DoDataStream(p2cPipe.readFd(), c2pPipe.writeFd()));
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.writeFd().reset();
+        c2pPipe.readFd().reset();
+        ASSERT_TRUE(DoDataStream(&p2cPipe.readFd(), &c2pPipe.writeFd()));
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
         _exit(EXIT_SUCCESS);
     } else {
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
 
-        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());
@@ -266,18 +268,18 @@
     ASSERT_TRUE(pid != -1);
 
     if (pid == 0) {
-        close(p2cPipe.writeFd());
-        close(c2pPipe.readFd());
+        p2cPipe.writeFd().reset();
+        c2pPipe.readFd().reset();
         while (true) {
             sleep(1);
         }
         _exit(EXIT_FAILURE);
     } else {
-        close(p2cPipe.readFd());
-        close(c2pPipe.writeFd());
+        p2cPipe.readFd().reset();
+        c2pPipe.writeFd().reset();
 
-        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(tf.fd, p2cPipe.writeFd(),
-                                                             c2pPipe.readFd(), QUICK_TIMEOUT_MS));
+        ASSERT_EQ(NO_ERROR, buffer.readProcessedDataInStream(&tffd, &p2cPipe.writeFd(),
+                                                             &c2pPipe.readFd(), QUICK_TIMEOUT_MS));
         EXPECT_TRUE(buffer.timedOut());
         kill(pid, SIGKILL);  // reap the child process
     }
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index c7c69a7..5edc0c7 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -58,7 +58,8 @@
 
     void writeToFdBuffer(string str) {
         ASSERT_TRUE(WriteStringToFile(str, tf.path));
-        ASSERT_EQ(NO_ERROR, buffer.read(tf.fd, 10000));
+        unique_fd tffd(tf.fd);
+        ASSERT_EQ(NO_ERROR, buffer.read(&tffd, 10000));
         ASSERT_EQ(str.size(), buffer.size());
     }
 
diff --git a/cmds/statsd/benchmark/filter_value_benchmark.cpp b/cmds/statsd/benchmark/filter_value_benchmark.cpp
index 66c4def..cfe477d 100644
--- a/cmds/statsd/benchmark/filter_value_benchmark.cpp
+++ b/cmds/statsd/benchmark/filter_value_benchmark.cpp
@@ -54,28 +54,12 @@
     translateFieldMatcher(field_matcher, &matchers);
 
     while (state.KeepRunning()) {
-        vector<HashableDimensionKey> output;
-        filterValues(matchers, event.getValues(), &output);
-    }
-}
-
-BENCHMARK(BM_FilterValue);
-
-static void BM_FilterValue2(benchmark::State& state) {
-    LogEvent event(1, 100000);
-    FieldMatcher field_matcher;
-    createLogEventAndMatcher(&event, &field_matcher);
-
-    std::vector<Matcher> matchers;
-    translateFieldMatcher(field_matcher, &matchers);
-
-    while (state.KeepRunning()) {
         HashableDimensionKey output;
         filterValues(matchers, event.getValues(), &output);
     }
 }
 
-BENCHMARK(BM_FilterValue2);
+BENCHMARK(BM_FilterValue);
 
 }  //  namespace statsd
 }  //  namespace os
diff --git a/cmds/statsd/src/FieldValue.cpp b/cmds/statsd/src/FieldValue.cpp
index 0c9b701..dfd8705 100644
--- a/cmds/statsd/src/FieldValue.cpp
+++ b/cmds/statsd/src/FieldValue.cpp
@@ -48,6 +48,11 @@
         return true;
     }
 
+    if (matcher.hasAllPositionMatcher() &&
+        (mField & (matcher.mMask & kClearAllPositionMatcherMask)) == matcher.mMatcher.getField()) {
+        return true;
+    }
+
     return false;
 }
 
@@ -67,6 +72,10 @@
             return;
         }
         switch (matcher.position()) {
+            case Position::ALL:
+                pos[depth] = 0x00;
+                mask[depth] = 0x7f;
+                break;
             case Position::ANY:
                 pos[depth] = 0;
                 mask[depth] = 0;
diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h
index 0e3ae06..f7ce23b 100644
--- a/cmds/statsd/src/FieldValue.h
+++ b/cmds/statsd/src/FieldValue.h
@@ -30,6 +30,7 @@
 const int32_t kMaxLogDepth = 2;
 const int32_t kLastBitMask = 0x80;
 const int32_t kClearLastBitDeco = 0x7f;
+const int32_t kClearAllPositionMatcherMask = 0xffff00ff;
 
 enum Type { UNKNOWN, INT, LONG, FLOAT, STRING };
 
@@ -205,6 +206,7 @@
  * First: [Matcher Field] 0x02010101  [Mask]0xff7f7f7f
  * Last:  [Matcher Field] 0x02018001  [Mask]0xff7f807f
  * Any:   [Matcher Field] 0x02010001  [Mask]0xff7f007f
+ * All:   [Matcher Field] 0x02010001  [Mask]0xff7f7f7f
  *
  * [To match a log Field with a Matcher] we apply the bit mask to the log Field and check if
  * the result is equal to the Matcher Field. That's a bit wise AND operation + check if 2 ints are
@@ -226,9 +228,21 @@
         return mMask;
     }
 
+    inline int32_t getRawMaskAtDepth(int32_t depth) const {
+        int32_t field = (mMask & 0x00ffffff);
+        int32_t shift = 8 * (kMaxLogDepth - depth);
+        int32_t mask = 0xff << shift;
+
+        return (field & mask) >> shift;
+    }
+
+    bool hasAllPositionMatcher() const {
+        return mMatcher.getDepth() == 2 && getRawMaskAtDepth(1) == 0x7f;
+    }
+
     bool hasAnyPositionMatcher(int* prefix) const {
-        if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) {
-            (*prefix) = mMatcher.getPrefix(2);
+        if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(1) == 0) {
+            (*prefix) = mMatcher.getPrefix(1);
             return true;
         }
         return false;
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index d0c8311..7103034 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -61,125 +61,22 @@
 
 bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
                   HashableDimensionKey* output) {
-    for (size_t i = 0; i < matcherFields.size(); ++i) {
-        const auto& matcher = matcherFields[i];
-        bool found = false;
-        for (const auto& value : values) {
+    size_t num_matches = 0;
+    for (const auto& value : values) {
+        for (size_t i = 0; i < matcherFields.size(); ++i) {
+            const auto& matcher = matcherFields[i];
             // TODO: potential optimization here to break early because all fields are naturally
             // sorted.
             if (value.mField.matches(matcher)) {
                 output->addValue(value);
-                output->mutableValue(i)->mField.setTag(value.mField.getTag());
-                output->mutableValue(i)->mField.setField(value.mField.getField() & matcher.mMask);
-                found = true;
-                break;
-            }
-        }
-
-        if (!found) {
-            VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(),
-                   matcher.mMatcher.getField());
-            return false;
-        }
-    }
-
-    return true;
-}
-
-// Filter fields using the matchers and output the results as a HashableDimensionKey.
-// Note: HashableDimensionKey is just a wrapper for vector<FieldValue>
-bool filterValues(const vector<Matcher>& matcherFields, const vector<FieldValue>& values,
-                  vector<HashableDimensionKey>* output) {
-    output->push_back(HashableDimensionKey());
-    // Top level is only tag id. Now take the real child matchers
-    int prevAnyMatcherPrefix = 0;
-    size_t prevPrevFanout = 0;
-    size_t prevFanout = 0;
-
-    // For each matcher get matched results.
-    vector<FieldValue> matchedResults(2);
-    for (const auto& matcher : matcherFields) {
-        size_t num_matches = 0;
-        for (const auto& value : values) {
-            // TODO: potential optimization here to break early because all fields are naturally
-            // sorted.
-            if (value.mField.matches(matcher)) {
-                if (num_matches >= matchedResults.size()) {
-                    matchedResults.resize(num_matches * 2);
-                }
-                matchedResults[num_matches].mField.setTag(value.mField.getTag());
-                matchedResults[num_matches].mField.setField(value.mField.getField() & matcher.mMask);
-                matchedResults[num_matches].mValue = value.mValue;
+                output->mutableValue(num_matches)->mField.setTag(value.mField.getTag());
+                output->mutableValue(num_matches)->mField.setField(
+                    value.mField.getField() & matcher.mMask);
                 num_matches++;
             }
         }
-
-        if (num_matches == 0) {
-            VLOG("We can't find a dimension value for matcher (%d)%#x.", matcher.mMatcher.getTag(),
-                   matcher.mMatcher.getField());
-            continue;
-        }
-
-        if (num_matches == 1) {
-            for (auto& dimension : *output) {
-                dimension.addValue(matchedResults[0]);
-            }
-            prevAnyMatcherPrefix = 0;
-            prevFanout = 0;
-            continue;
-        }
-
-        // All the complexity below is because we support ANY in dimension.
-        bool createFanout = true;
-        // createFanout is true when the matcher doesn't need to follow the prev matcher's
-        // order.
-        // e.g., get (uid, tag) from any position in attribution. because we have translated
-        // it as 2 matchers, they need to follow the same ordering, we can't create a cross
-        // product of all uid and tags.
-        // However, if the 2 matchers have different prefix, they will create a cross product
-        // e.g., [any uid] [any some other repeated field], we will create a cross product for them
-        if (prevAnyMatcherPrefix != 0) {
-            int anyMatcherPrefix = 0;
-            bool isAnyMatcher = matcher.hasAnyPositionMatcher(&anyMatcherPrefix);
-            if (isAnyMatcher && anyMatcherPrefix == prevAnyMatcherPrefix) {
-                createFanout = false;
-            } else {
-                prevAnyMatcherPrefix = anyMatcherPrefix;
-            }
-        }
-
-        // Each matcher should match exact one field, unless position is ANY
-        // When x number of fields matches a matcher, the returned dimension
-        // size is multiplied by x.
-        int oldSize;
-        if (createFanout) {
-            // First create fanout (fanout size is matchedResults.Size which could be one,
-            // which means we do nothing here)
-            oldSize = output->size();
-            for (size_t i = 1; i < num_matches; i++) {
-                output->insert(output->end(), output->begin(), output->begin() + oldSize);
-            }
-            prevPrevFanout = oldSize;
-            prevFanout = num_matches;
-        } else {
-            // If we should not create fanout, e.g., uid tag from same position should be remain
-            // together.
-            oldSize = prevPrevFanout;
-            if (prevFanout != num_matches) {
-                // sanity check.
-                ALOGE("2 Any matcher result in different output");
-                return false;
-            }
-        }
-        // now add the matched field value to output
-        for (size_t i = 0; i < num_matches; i++) {
-            for (int j = 0; j < oldSize; j++) {
-                (*output)[i * oldSize + j].addValue(matchedResults[i]);
-            }
-        }
     }
-
-    return output->size() > 0 && (*output)[0].getValues().size() > 0;
+    return num_matches > 0;
 }
 
 void filterGaugeValues(const std::vector<Matcher>& matcherFields,
diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h
index 4cfed88..6f4941f 100644
--- a/cmds/statsd/src/HashableDimensionKey.h
+++ b/cmds/statsd/src/HashableDimensionKey.h
@@ -122,17 +122,14 @@
 /**
  * Creating HashableDimensionKeys from FieldValues using matcher.
  *
- * This function may make modifications to the Field if the matcher has Position=LAST or ANY in
- * it. This is because: for example, when we create dimension from last uid in attribution chain,
+ * This function may make modifications to the Field if the matcher has Position=FIRST,LAST or ALL
+ * in it. This is because: for example, when we create dimension from last uid in attribution chain,
  * In one event, uid 1000 is at position 5 and it's the last
  * In another event, uid 1000 is at position 6, and it's the last
  * these 2 events should be mapped to the same dimension.  So we will remove the original position
  * from the dimension key for the uid field (by applying 0x80 bit mask).
  */
 bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
-                  std::vector<HashableDimensionKey>* output);
-// This function is used when there is at most one output dimension key. (no ANY matcher)
-bool filterValues(const std::vector<Matcher>& matcherFields, const std::vector<FieldValue>& values,
                   HashableDimensionKey* output);
 
 /**
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 8db8200..8b42146 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -121,7 +121,8 @@
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForMaxDuration3);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks1);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks2);
-    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
+    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
+    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
     FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
@@ -138,6 +139,7 @@
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_NoLink_AND_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestDurationMetric_Link_AND_CombinationCondition);
 
+
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 4913aef..73efb39 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -327,25 +327,7 @@
         // have both sliced and unsliced version of a predicate.
         handleConditionEvent(outputValue, matchedState == 1, &overallState, &overallChanged);
     } else {
-        std::vector<HashableDimensionKey> outputValues;
-        filterValues(mOutputDimensions, event.getValues(), &outputValues);
-
-        // If this event has multiple nodes in the attribution chain,  this log event probably will
-        // generate multiple dimensions. If so, we will find if the condition changes for any
-        // dimension and ask the corresponding metric producer to verify whether the actual sliced
-        // condition has changed or not.
-        // A high level assumption is that a predicate is either sliced or unsliced. We will never
-        // have both sliced and unsliced version of a predicate.
-        for (const HashableDimensionKey& outputValue : outputValues) {
-            ConditionState tempState;
-            bool tempChanged = false;
-            handleConditionEvent(outputValue, matchedState == 1, &tempState, &tempChanged);
-            if (tempChanged) {
-                overallChanged = true;
-            }
-            // ConditionState's | operator is overridden
-            overallState = overallState | tempState;
-        }
+        ALOGE("The condition tracker should not be sliced by ANY position matcher.");
     }
     conditionCache[mIndex] = overallState;
     conditionChangedCache[mIndex] = overallChanged;
diff --git a/cmds/statsd/src/condition/StateTracker.cpp b/cmds/statsd/src/condition/StateTracker.cpp
index c68875c..fe1740b 100644
--- a/cmds/statsd/src/condition/StateTracker.cpp
+++ b/cmds/statsd/src/condition/StateTracker.cpp
@@ -137,21 +137,18 @@
 
     VLOG("StateTracker evaluate event %s", event.ToString().c_str());
 
-    vector<HashableDimensionKey> keys;
-    vector<HashableDimensionKey> outputs;
-    filterValues(mPrimaryKeys, event.getValues(), &keys);
-    filterValues(mOutputDimensions, event.getValues(), &outputs);
-    if (keys.size() != 1 || outputs.size() != 1) {
-        ALOGE("More than 1 states in the event?? panic now!");
+    // Primary key can exclusive fields must be simple fields. so there won't be more than
+    // one keys matched.
+    HashableDimensionKey primaryKey;
+    HashableDimensionKey state;
+    if (!filterValues(mPrimaryKeys, event.getValues(), &primaryKey) ||
+        !filterValues(mOutputDimensions, event.getValues(), &state)) {
+        ALOGE("Failed to filter fields in the event?? panic now!");
         conditionCache[mIndex] =
                 mSlicedState.size() > 0 ? ConditionState::kTrue : ConditionState::kFalse;
         conditionChangedCache[mIndex] = false;
         return;
     }
-    // Primary key can exclusive fields must be simple fields. so there won't be more than
-    // one keys matched.
-    const auto& primaryKey = keys[0];
-    const auto& state = outputs[0];
     hitGuardRail(primaryKey);
 
     VLOG("StateTracker: key %s state %s", primaryKey.toString().c_str(), state.toString().c_str());
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index c6c4d13..7a55f60 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -21,6 +21,7 @@
 #include <android/util/ProtoOutputStream.h>
 #include "../stats_log_util.h"
 #include "statslog.h"
+#include "storage/StorageManager.h"
 
 namespace android {
 namespace os {
@@ -403,6 +404,8 @@
             fprintf(out, "alert %lld declared %d times\n", (long long)stats.first, stats.second);
         }
     }
+    fprintf(out, "********Disk Usage stats***********\n");
+    StorageManager::printStats(out);
     fprintf(out, "********Pushed Atom stats***********\n");
     const size_t atomCounts = mPushedAtomStats.size();
     for (size_t i = 2; i < atomCounts; i++) {
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 364d4e9..b7105b3 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -185,6 +185,9 @@
                 ranges.push_back(std::make_pair(newStart, end));
                 break;
             }
+            case Position::ALL:
+                ALOGE("Not supported: field matcher with ALL position.");
+                break;
             case Position::POSITION_UNKNOWN:
                 break;
         }
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index bc09683..c6b9405 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -88,6 +88,12 @@
         translateFieldMatcher(internalDimensions, &mInternalDimensions);
         mContainANYPositionInInternalDimensions = HasPositionANY(internalDimensions);
     }
+    if (mContainANYPositionInInternalDimensions) {
+        ALOGE("Position ANY in internal dimension not supported.");
+    }
+    if (mContainANYPositionInDimensionsInWhat) {
+        ALOGE("Position ANY in dimension_in_what not supported.");
+    }
 
     if (metric.has_dimensions_in_condition()) {
         translateFieldMatcher(metric.dimensions_in_condition(), &mDimensionsInCondition);
@@ -589,18 +595,10 @@
         it->second->noteStart(DEFAULT_DIMENSION_KEY, condition,
                               event.GetElapsedTimestampNs(), conditionKeys);
     } else {
-        if (mContainANYPositionInInternalDimensions) {
-            std::vector<HashableDimensionKey> dimensionKeys;
-            filterValues(mInternalDimensions, event.getValues(), &dimensionKeys);
-            for (const auto& key : dimensionKeys) {
-                it->second->noteStart(key, condition, event.GetElapsedTimestampNs(), conditionKeys);
-            }
-        } else {
-            HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
-            filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
-            it->second->noteStart(
-                dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
-        }
+        HashableDimensionKey dimensionKey = DEFAULT_DIMENSION_KEY;
+        filterValues(mInternalDimensions, event.getValues(), &dimensionKey);
+        it->second->noteStart(
+            dimensionKey, condition, event.GetElapsedTimestampNs(), conditionKeys);
     }
 
 }
@@ -612,8 +610,8 @@
     ALOGW("Not used in duration tracker.");
 }
 
-void DurationMetricProducer::onMatchedLogEventLocked_simple(const size_t matcherIndex,
-                                                            const LogEvent& event) {
+void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
+                                                     const LogEvent& event) {
     uint64_t eventTimeNs = event.GetElapsedTimestampNs();
     if (eventTimeNs < mStartTimeNs) {
         return;
@@ -712,117 +710,6 @@
     }
 }
 
-void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex,
-                                                     const LogEvent& event) {
-    if (!mContainANYPositionInDimensionsInWhat) {
-        onMatchedLogEventLocked_simple(matcherIndex, event);
-        return;
-    }
-
-    uint64_t eventTimeNs = event.GetElapsedTimestampNs();
-    if (eventTimeNs < mStartTimeNs) {
-        return;
-    }
-
-    flushIfNeededLocked(event.GetElapsedTimestampNs());
-
-    // Handles Stopall events.
-    if (matcherIndex == mStopAllIndex) {
-        for (auto& whatIt : mCurrentSlicedDurationTrackerMap) {
-            for (auto& pair : whatIt.second) {
-                pair.second->noteStopAll(event.GetElapsedTimestampNs());
-            }
-        }
-        return;
-    }
-
-    vector<HashableDimensionKey> dimensionInWhatValues;
-    if (!mDimensionsInWhat.empty()) {
-        filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
-    } else {
-        dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
-    }
-
-    // Handles Stop events.
-    if (matcherIndex == mStopIndex) {
-        if (mUseWhatDimensionAsInternalDimension) {
-            for (const HashableDimensionKey& whatKey : dimensionInWhatValues) {
-                auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey);
-                if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-                    for (const auto& condIt : whatIt->second) {
-                        condIt.second->noteStop(whatKey, event.GetElapsedTimestampNs(), false);
-                    }
-                }
-            }
-            return;
-        }
-
-        HashableDimensionKey internalDimensionKey = DEFAULT_DIMENSION_KEY;
-        if (!mInternalDimensions.empty()) {
-            filterValues(mInternalDimensions, event.getValues(), &internalDimensionKey);
-        }
-
-        for (const HashableDimensionKey& whatDimension : dimensionInWhatValues) {
-            auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
-            if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-                for (const auto& condIt : whatIt->second) {
-                    condIt.second->noteStop(
-                        internalDimensionKey, event.GetElapsedTimestampNs(), false);
-                }
-            }
-        }
-        return;
-    }
-
-    bool condition;
-    ConditionKey conditionKey;
-    std::unordered_set<HashableDimensionKey> dimensionKeysInCondition;
-    if (mConditionSliced) {
-        for (const auto& link : mMetric2ConditionLinks) {
-            getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]);
-        }
-
-        auto conditionState =
-            mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition,
-                           !mSameConditionDimensionsInTracker,
-                           !mHasLinksToAllConditionDimensionsInTracker,
-                           &dimensionKeysInCondition);
-        condition = (conditionState == ConditionState::kTrue);
-        if (mDimensionsInCondition.empty() && condition) {
-            dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
-        }
-    } else {
-        condition = mCondition;
-        if (condition) {
-            dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
-        }
-    }
-
-    for (const auto& whatDimension : dimensionInWhatValues) {
-        if (dimensionKeysInCondition.empty()) {
-            handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
-                             conditionKey, condition, event);
-        } else {
-            auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension);
-            // If the what dimension is already there, we should update all the trackers even
-            // the condition is false.
-            if (whatIt != mCurrentSlicedDurationTrackerMap.end()) {
-                for (const auto& condIt : whatIt->second) {
-                    const bool cond = dimensionKeysInCondition.find(condIt.first) !=
-                            dimensionKeysInCondition.end();
-                    handleStartEvent(MetricDimensionKey(whatDimension, condIt.first),
-                                     conditionKey, cond, event);
-                    dimensionKeysInCondition.erase(condIt.first);
-                }
-            }
-            for (const auto& conditionDimension : dimensionKeysInCondition) {
-                handleStartEvent(MetricDimensionKey(whatDimension, conditionDimension),
-                                 conditionKey, condition, event);
-            }
-        }
-    }
-}
-
 size_t DurationMetricProducer::byteSizeLocked() const {
     size_t totalSize = 0;
     for (const auto& pair : mPastBuckets) {
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 6746e11..985749d 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -52,8 +52,6 @@
 protected:
     void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override;
 
-    void onMatchedLogEventLocked_simple(const size_t matcherIndex, const LogEvent& event);
-
     void onMatchedLogEventInternalLocked(
             const size_t matcherIndex, const MetricDimensionKey& eventKey,
             const ConditionKey& conditionKeys, bool condition,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 6c90b03..f4495a1 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -53,39 +53,17 @@
         dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY);
     }
 
-    if (mContainANYPositionInDimensionsInWhat) {
-        vector<HashableDimensionKey> dimensionInWhatValues;
-        if (!mDimensionsInWhat.empty()) {
-            filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues);
-        } else {
-            dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY);
-        }
-
-        for (const auto& whatDimension : dimensionInWhatValues) {
-            for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
-                onMatchedLogEventInternalLocked(
-                        matcherIndex, MetricDimensionKey(whatDimension, conditionDimensionKey),
-                        conditionKey, condition, event);
-            }
-            if (dimensionKeysInCondition.empty()) {
-                onMatchedLogEventInternalLocked(
-                        matcherIndex, MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY),
-                         conditionKey, condition, event);
-            }
-        }
-    } else {
-        HashableDimensionKey dimensionInWhat;
-        filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
-        MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
-        for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
-            metricKey.setDimensionKeyInCondition(conditionDimensionKey);
-            onMatchedLogEventInternalLocked(
-                    matcherIndex, metricKey, conditionKey, condition, event);
-        }
-        if (dimensionKeysInCondition.empty()) {
-            onMatchedLogEventInternalLocked(
-                    matcherIndex, metricKey, conditionKey, condition, event);
-        }
+    HashableDimensionKey dimensionInWhat;
+    filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhat);
+    MetricDimensionKey metricKey(dimensionInWhat, DEFAULT_DIMENSION_KEY);
+    for (const auto& conditionDimensionKey : dimensionKeysInCondition) {
+        metricKey.setDimensionKeyInCondition(conditionDimensionKey);
+        onMatchedLogEventInternalLocked(
+                matcherIndex, metricKey, conditionKey, condition, event);
+    }
+    if (dimensionKeysInCondition.empty()) {
+        onMatchedLogEventInternalLocked(
+                matcherIndex, metricKey, conditionKey, condition, event);
     }
 
  }
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index bebd53c..46a9b34 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -163,7 +163,8 @@
 
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
-    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSlice);
+    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
+    FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain);
     FRIEND_TEST(GaugeMetricE2eTest, TestMultipleFieldsForPushedEvent);
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_NoLink_OR_CombinationCondition);
     FRIEND_TEST(DimensionInConditionE2eTest, TestCreateCountMetric_Link_OR_CombinationCondition);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 1c99e2a..2c70191 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -31,6 +31,8 @@
   LAST = 2;
 
   ANY = 3;
+
+  ALL = 4;
 }
 
 enum TimeUnit {
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 77387cb..cd41f53 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -345,6 +345,53 @@
     }
 }
 
+void StorageManager::printStats(FILE* out) {
+    printDirStats(out, STATS_SERVICE_DIR);
+    printDirStats(out, STATS_DATA_DIR);
+}
+
+void StorageManager::printDirStats(FILE* out, const char* path) {
+    fprintf(out, "Printing stats of %s\n", path);
+    unique_ptr<DIR, decltype(&closedir)> dir(opendir(path), closedir);
+    if (dir == NULL) {
+        VLOG("Path %s does not exist", path);
+        return;
+    }
+    dirent* de;
+    int fileCount = 0;
+    int totalFileSize = 0;
+    while ((de = readdir(dir.get()))) {
+        char* name = de->d_name;
+        if (name[0] == '.') {
+            continue;
+        }
+        int64_t result[3];
+        parseFileName(name, result);
+        if (result[0] == -1) continue;
+        int64_t timestamp = result[0];
+        int64_t uid = result[1];
+        int64_t configID = result[2];
+        fprintf(out, "\t #%d, Last updated: %lld, UID: %d, Config ID: %lld",
+                fileCount + 1,
+                (long long)timestamp,
+                (int)uid,
+                (long long)configID);
+        string file_name = getFilePath(path, timestamp, uid, configID);
+        ifstream file(file_name.c_str(), ifstream::in | ifstream::binary);
+        if (file.is_open()) {
+            file.seekg(0, ios::end);
+            int fileSize = file.tellg();
+            file.close();
+            fprintf(out, ", File Size: %d bytes", fileSize);
+            totalFileSize += fileSize;
+        }
+        fprintf(out, "\n");
+        fileCount++;
+    }
+    fprintf(out, "\tTotal number of files: %d, Total size of files: %d bytes.\n",
+            fileCount, totalFileSize);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 13ce5c6..4b75628 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -84,6 +84,17 @@
      */
     static bool hasIdenticalConfig(const ConfigKey& key,
                                    const vector<uint8_t>& config);
+
+    /**
+     * Prints disk usage statistics related to statsd.
+     */
+    static void printStats(FILE* out);
+
+private:
+    /**
+     * Prints disk usage statistics about a directory related to statsd.
+     */
+    static void printDirStats(FILE* out, const char* path);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/FieldValue_test.cpp b/cmds/statsd/tests/FieldValue_test.cpp
index 5846761..73e7c44 100644
--- a/cmds/statsd/tests/FieldValue_test.cpp
+++ b/cmds/statsd/tests/FieldValue_test.cpp
@@ -45,20 +45,41 @@
 
     const auto& matcher12 = output[0];
     EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
-    EXPECT_EQ((int32_t)0x2010001, matcher12.mMatcher.getField());
+    EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
     EXPECT_EQ((int32_t)0xff7f007f, matcher12.mMask);
 }
 
-TEST(AtomMatcherTest, TestFilter) {
+TEST(AtomMatcherTest, TestFieldTranslation_ALL) {
     FieldMatcher matcher1;
     matcher1.set_field(10);
     FieldMatcher* child = matcher1.add_child();
     child->set_field(1);
-    child->set_position(Position::ANY);
+    child->set_position(Position::ALL);
 
     child = child->add_child();
     child->set_field(1);
 
+    vector<Matcher> output;
+    translateFieldMatcher(matcher1, &output);
+
+    EXPECT_EQ((size_t)1, output.size());
+
+    const auto& matcher12 = output[0];
+    EXPECT_EQ((int32_t)10, matcher12.mMatcher.getTag());
+    EXPECT_EQ((int32_t)0x02010001, matcher12.mMatcher.getField());
+    EXPECT_EQ((int32_t)0xff7f7f7f, matcher12.mMask);
+}
+
+TEST(AtomMatcherTest, TestFilter_ALL) {
+    FieldMatcher matcher1;
+    matcher1.set_field(10);
+    FieldMatcher* child = matcher1.add_child();
+    child->set_field(1);
+    child->set_position(Position::ALL);
+
+    child->add_child()->set_field(1);
+    child->add_child()->set_field(2);
+
     child = matcher1.add_child();
     child->set_field(2);
 
@@ -85,32 +106,28 @@
     event.write("some value");
     // Convert to a LogEvent
     event.init();
-    vector<HashableDimensionKey> output;
+    HashableDimensionKey output;
 
     filterValues(matchers, event.getValues(), &output);
 
-    EXPECT_EQ((size_t)(3), output.size());
+    EXPECT_EQ((size_t)7, output.getValues().size());
+    EXPECT_EQ((int32_t)0x02010101, output.getValues()[0].mField.getField());
+    EXPECT_EQ((int32_t)1111, output.getValues()[0].mValue.int_value);
+    EXPECT_EQ((int32_t)0x02010102, output.getValues()[1].mField.getField());
+    EXPECT_EQ("location1", output.getValues()[1].mValue.str_value);
 
-    const auto& key1 = output[0];
-    EXPECT_EQ((size_t)2, key1.getValues().size());
-    EXPECT_EQ((int32_t)0x02010001, key1.getValues()[0].mField.getField());
-    EXPECT_EQ((int32_t)1111, key1.getValues()[0].mValue.int_value);
-    EXPECT_EQ((int32_t)0x00020000, key1.getValues()[1].mField.getField());
-    EXPECT_EQ("some value", key1.getValues()[1].mValue.str_value);
+    EXPECT_EQ((int32_t)0x02010201, output.getValues()[2].mField.getField());
+    EXPECT_EQ((int32_t)2222, output.getValues()[2].mValue.int_value);
+    EXPECT_EQ((int32_t)0x02010202, output.getValues()[3].mField.getField());
+    EXPECT_EQ("location2", output.getValues()[3].mValue.str_value);
 
-    const auto& key2 = output[1];
-    EXPECT_EQ((size_t)2, key2.getValues().size());
-    EXPECT_EQ((int32_t)0x02010001, key2.getValues()[0].mField.getField());
-    EXPECT_EQ((int32_t)2222, key2.getValues()[0].mValue.int_value);
-    EXPECT_EQ((int32_t)0x00020000, key2.getValues()[1].mField.getField());
-    EXPECT_EQ("some value", key2.getValues()[1].mValue.str_value);
+    EXPECT_EQ((int32_t)0x02010301, output.getValues()[4].mField.getField());
+    EXPECT_EQ((int32_t)3333, output.getValues()[4].mValue.int_value);
+    EXPECT_EQ((int32_t)0x02010302, output.getValues()[5].mField.getField());
+    EXPECT_EQ("location3", output.getValues()[5].mValue.str_value);
 
-    const auto& key3 = output[2];
-    EXPECT_EQ((size_t)2, key3.getValues().size());
-    EXPECT_EQ((int32_t)0x02010001, key3.getValues()[0].mField.getField());
-    EXPECT_EQ((int32_t)3333, key3.getValues()[0].mValue.int_value);
-    EXPECT_EQ((int32_t)0x00020000, key3.getValues()[1].mField.getField());
-    EXPECT_EQ("some value", key3.getValues()[1].mValue.str_value);
+    EXPECT_EQ((int32_t)0x00020000, output.getValues()[6].mField.getField());
+    EXPECT_EQ("some value", output.getValues()[6].mValue.str_value);
 }
 
 TEST(AtomMatcherTest, TestSubDimension) {
diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
index 7a7e000..2574ba7 100644
--- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp
@@ -28,7 +28,7 @@
 
 namespace {
 
-StatsdConfig CreateStatsdConfig() {
+StatsdConfig CreateStatsdConfig(const Position position) {
     StatsdConfig config;
     auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
     auto attributionNodeMatcher =
@@ -46,15 +46,15 @@
     countMetric->set_what(wakelockAcquireMatcher.id());
     *countMetric->mutable_dimensions_in_what() =
         CreateAttributionUidAndTagDimensions(
-            android::util::WAKELOCK_STATE_CHANGED, {Position::FIRST});
+            android::util::WAKELOCK_STATE_CHANGED, {position});
     countMetric->set_bucket(FIVE_MINUTES);
     return config;
 }
 
 }  // namespace
 
-TEST(AttributionE2eTest, TestAttributionMatchAndSlice) {
-    auto config = CreateStatsdConfig();
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) {
+    auto config = CreateStatsdConfig(Position::FIRST);
     int64_t bucketStartTimeNs = 10000000000;
     int64_t bucketSizeNs =
         TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
@@ -199,6 +199,215 @@
     EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + 3 * bucketSizeNs);
 }
 
+TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) {
+    auto config = CreateStatsdConfig(Position::ALL);
+    int64_t bucketStartTimeNs = 10000000000;
+    int64_t bucketSizeNs =
+        TimeUnitToBucketSizeInMillis(config.count_metric(0).bucket()) * 1000000;
+
+    ConfigKey cfgKey;
+    auto processor = CreateStatsLogProcessor(bucketStartTimeNs / NS_PER_SEC, config, cfgKey);
+    EXPECT_EQ(processor->mMetricsManagers.size(), 1u);
+    EXPECT_TRUE(processor->mMetricsManagers.begin()->second->isConfigValid());
+
+    // Here it assumes that GMS core has two uids.
+    processor->getUidMap()->updateApp(
+        android::String16("com.android.gmscore"), 222 /* uid */, 1 /* version code*/);
+    processor->getUidMap()->updateApp(
+        android::String16("com.android.gmscore"), 444 /* uid */, 1 /* version code*/);
+    processor->getUidMap()->updateApp(
+        android::String16("app1"), 111 /* uid */, 2 /* version code*/);
+    processor->getUidMap()->updateApp(
+        android::String16("APP3"), 333 /* uid */, 2 /* version code*/);
+
+    // GMS core node is in the middle.
+    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1"),
+                                                          CreateAttribution(222, "GMSCoreModule1"),
+                                                          CreateAttribution(333, "App3")};
+
+    // GMS core node is the last one.
+    std::vector<AttributionNodeInternal> attributions2 = {CreateAttribution(111, "App1"),
+                                                          CreateAttribution(333, "App3"),
+                                                          CreateAttribution(222, "GMSCoreModule1")};
+
+    // GMS core node is the first one.
+    std::vector<AttributionNodeInternal> attributions3 = {CreateAttribution(222, "GMSCoreModule1"),
+                                                          CreateAttribution(333, "App3")};
+
+    // Single GMS core node.
+    std::vector<AttributionNodeInternal> attributions4 = {CreateAttribution(222, "GMSCoreModule1")};
+
+    // GMS core has another uid.
+    std::vector<AttributionNodeInternal> attributions5 = {CreateAttribution(111, "App1"),
+                                                          CreateAttribution(444, "GMSCoreModule2"),
+                                                          CreateAttribution(333, "App3")};
+
+    // Multiple GMS core nodes.
+    std::vector<AttributionNodeInternal> attributions6 = {CreateAttribution(444, "GMSCoreModule2"),
+                                                          CreateAttribution(222, "GMSCoreModule1")};
+
+    // No GMS core nodes.
+    std::vector<AttributionNodeInternal> attributions7 = {CreateAttribution(111, "App1"),
+                                                          CreateAttribution(333, "App3")};
+    std::vector<AttributionNodeInternal> attributions8 = {CreateAttribution(111, "App1")};
+
+    // GMS core node with isolated uid.
+    const int isolatedUid = 666;
+    std::vector<AttributionNodeInternal> attributions9 = {
+            CreateAttribution(isolatedUid, "GMSCoreModule1")};
+
+    std::vector<std::unique_ptr<LogEvent>> events;
+    // Events 1~4 are in the 1st bucket.
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions1, "wl1", bucketStartTimeNs + 2));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions2, "wl1", bucketStartTimeNs + 200));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions3, "wl1", bucketStartTimeNs + bucketSizeNs - 1));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions4, "wl1", bucketStartTimeNs + bucketSizeNs));
+
+    // Events 5~8 are in the 3rd bucket.
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions5, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 1));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions6, "wl2", bucketStartTimeNs + 2 * bucketSizeNs + 100));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions7, "wl2", bucketStartTimeNs + 3 * bucketSizeNs - 2));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions8, "wl2", bucketStartTimeNs + 3 * bucketSizeNs));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 1));
+    events.push_back(CreateAcquireWakelockEvent(
+        attributions9, "wl2", bucketStartTimeNs + 3 * bucketSizeNs + 100));
+    events.push_back(CreateIsolatedUidChangedEvent(
+        isolatedUid, 222, true/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs - 1));
+    events.push_back(CreateIsolatedUidChangedEvent(
+        isolatedUid, 222, false/* is_create*/, bucketStartTimeNs + 3 * bucketSizeNs + 10));
+
+    sortLogEventsByTimestamp(&events);
+
+    for (const auto& event : events) {
+        processor->OnLogEvent(event.get());
+    }
+    ConfigMetricsReportList reports;
+    vector<uint8_t> buffer;
+    processor->onDumpReport(cfgKey, bucketStartTimeNs + 4 * bucketSizeNs + 1, &buffer);
+    EXPECT_TRUE(buffer.size() > 0);
+    EXPECT_TRUE(reports.ParseFromArray(&buffer[0], buffer.size()));
+    EXPECT_EQ(reports.reports_size(), 1);
+    EXPECT_EQ(reports.reports(0).metrics_size(), 1);
+
+    StatsLogReport::CountMetricDataWrapper countMetrics;
+    sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics);
+    EXPECT_EQ(countMetrics.data_size(), 6);
+
+    auto data = countMetrics.data(0);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+    EXPECT_EQ(2, data.bucket_info_size());
+    EXPECT_EQ(1, data.bucket_info(0).count());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+    EXPECT_EQ(1, data.bucket_info(1).count());
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+              data.bucket_info(1).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 4 * bucketSizeNs,
+              data.bucket_info(1).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(1);
+    ValidateUidDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(data.bucket_info(0).start_bucket_elapsed_nanos(), bucketStartTimeNs);
+    EXPECT_EQ(data.bucket_info(0).end_bucket_elapsed_nanos(), bucketStartTimeNs + bucketSizeNs);
+
+    data = countMetrics.data(2);
+    ValidateUidDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(3);
+    ValidateUidDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(4);
+    ValidateUidDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 222, "GMSCoreModule1");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + bucketSizeNs,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+
+    data = countMetrics.data(5);
+    ValidateUidDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 0, android::util::WAKELOCK_STATE_CHANGED, 111, "App1");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 1, android::util::WAKELOCK_STATE_CHANGED, 444, "GMSCoreModule2");
+    ValidateUidDimension(
+        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333);
+    ValidateAttributionUidAndTagDimension(
+        data.dimensions_in_what(), 2, android::util::WAKELOCK_STATE_CHANGED, 333, "App3");
+    EXPECT_EQ(data.bucket_info_size(), 1);
+    EXPECT_EQ(data.bucket_info(0).count(), 1);
+    EXPECT_EQ(bucketStartTimeNs + 2 * bucketSizeNs,
+              data.bucket_info(0).start_bucket_elapsed_nanos());
+    EXPECT_EQ(bucketStartTimeNs + 3 * bucketSizeNs,
+              data.bucket_info(0).end_bucket_elapsed_nanos());
+}
+
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp
index 2678c8a..0f785df 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -500,12 +500,42 @@
         .value_tuple().dimensions_value(0).value_int(), uid);
 }
 
+void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid) {
+    EXPECT_EQ(value.field(), atomId);
+    EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx);
+    // Attribution field.
+    EXPECT_EQ(value.value_tuple().dimensions_value(node_idx).field(), 1);
+    EXPECT_EQ(value.value_tuple().dimensions_value(node_idx)
+        .value_tuple().dimensions_value(0).field(), 1);
+    EXPECT_EQ(value.value_tuple().dimensions_value(node_idx)
+        .value_tuple().dimensions_value(0).value_int(), uid);
+}
+
+void ValidateAttributionUidAndTagDimension(
+    const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag) {
+    EXPECT_EQ(value.field(), atomId);
+    EXPECT_GT(value.value_tuple().dimensions_value_size(), node_idx);
+    // Attribution field.
+    EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx).field());
+    // Uid only.
+    EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx)
+        .value_tuple().dimensions_value_size());
+    EXPECT_EQ(1, value.value_tuple().dimensions_value(node_idx)
+        .value_tuple().dimensions_value(0).field());
+    EXPECT_EQ(uid, value.value_tuple().dimensions_value(node_idx)
+        .value_tuple().dimensions_value(0).value_int());
+    EXPECT_EQ(2, value.value_tuple().dimensions_value(node_idx)
+        .value_tuple().dimensions_value(1).field());
+    EXPECT_EQ(tag, value.value_tuple().dimensions_value(node_idx)
+        .value_tuple().dimensions_value(1).value_str());
+}
+
 void ValidateAttributionUidAndTagDimension(
     const DimensionsValue& value, int atomId, int uid, const std::string& tag) {
     EXPECT_EQ(value.field(), atomId);
-    EXPECT_EQ(value.value_tuple().dimensions_value_size(), 1);
+    EXPECT_EQ(1, value.value_tuple().dimensions_value_size());
     // Attribution field.
-    EXPECT_EQ(value.value_tuple().dimensions_value(0).field(), 1);
+    EXPECT_EQ(1, value.value_tuple().dimensions_value(0).field());
     // Uid only.
     EXPECT_EQ(value.value_tuple().dimensions_value(0)
         .value_tuple().dimensions_value_size(), 2);
diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h
index 14eba1f..1ac630c 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -180,9 +180,12 @@
 
 int64_t StringToId(const string& str);
 
+void ValidateUidDimension(const DimensionsValue& value, int node_idx, int atomId, int uid);
 void ValidateAttributionUidDimension(const DimensionsValue& value, int atomId, int uid);
 void ValidateAttributionUidAndTagDimension(
     const DimensionsValue& value, int atomId, int uid, const std::string& tag);
+void ValidateAttributionUidAndTagDimension(
+    const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag);
 
 struct DimensionsPair {
     DimensionsPair(DimensionsValue m1, DimensionsValue m2) : dimInWhat(m1), dimInCondition(m2){};
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index 9f71f26..06e108c5 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -96,6 +96,7 @@
 Landroid/app/ActivityThread;->mNumVisibleActivities:I
 Landroid/app/ActivityThread;->mPackages:Landroid/util/ArrayMap;
 Landroid/app/ActivityThread;->mProviderMap:Landroid/util/ArrayMap;
+Landroid/app/ActivityThread;->mResourcePackages: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
@@ -116,6 +117,7 @@
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;ZI)V
 Landroid/app/admin/DevicePolicyManager;->setActiveAdmin(Landroid/content/ComponentName;Z)V
 Landroid/app/admin/DevicePolicyManager;->throwIfParentInstance(Ljava/lang/String;)V
+Landroid/app/admin/DevicePolicyManager;->setDefaultSmsApplication(Landroid/content/ComponentName;Ljava/lang/String;)V
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_packageHasActiveAdmins:I
 Landroid/app/admin/IDevicePolicyManager$Stub;->TRANSACTION_removeActiveAdmin:I
 Landroid/app/admin/SecurityLog$SecurityEvent;-><init>([B)V
@@ -502,6 +504,7 @@
 Landroid/content/res/Resources;->setCompatibilityInfo(Landroid/content/res/CompatibilityInfo;)V
 Landroid/content/res/Resources;->updateSystemConfiguration(Landroid/content/res/Configuration;Landroid/util/DisplayMetrics;Landroid/content/res/CompatibilityInfo;)V
 Landroid/content/res/StringBlock;-><init>(JZ)V
+Landroid/content/res/TypedArray;->extractThemeAttrs()[I
 Landroid/content/res/TypedArray;->getNonConfigurationString(II)Ljava/lang/String;
 Landroid/content/res/TypedArray;->getValueAt(ILandroid/util/TypedValue;)Z
 Landroid/content/res/TypedArray;->mAssets:Landroid/content/res/AssetManager;
@@ -518,6 +521,7 @@
 Landroid/content/res/XmlBlock;->newParser()Landroid/content/res/XmlResourceParser;
 Landroid/content/res/XmlBlock$Parser;->mBlock:Landroid/content/res/XmlBlock;
 Landroid/content/res/XmlBlock$Parser;->mParseState:J
+Landroid/content/SearchRecentSuggestionsProvider;->mSuggestionProjection:[Ljava/lang/String;
 Landroid/content/SyncStatusInfo;->lastSuccessTime:J
 Landroid/database/AbstractCursor;->mExtras:Landroid/os/Bundle;
 Landroid/database/AbstractCursor;->mNotifyUri:Landroid/net/Uri;
@@ -556,6 +560,7 @@
 Landroid/graphics/Camera;->native_instance:J
 Landroid/graphics/Canvas;-><init>(J)V
 Landroid/graphics/Canvas;->release()V
+Landroid/graphics/ColorMatrixColorFilter;->setColorMatrix(Landroid/graphics/ColorMatrix;)V
 Landroid/graphics/drawable/AnimatedImageDrawable;->onAnimationEnd()V
 Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mStateIds:Landroid/util/SparseIntArray;
 Landroid/graphics/drawable/AnimatedStateListDrawable$AnimatedStateListState;->mTransitions:Landroid/util/LongSparseLongArray;
@@ -622,6 +627,8 @@
 Landroid/graphics/NinePatch$InsetStruct;-><init>(IIIIIIIIFIF)V
 Landroid/graphics/NinePatch;->mBitmap:Landroid/graphics/Bitmap;
 Landroid/graphics/Picture;->mNativePicture:J
+Landroid/graphics/PorterDuffColorFilter;->setColor(I)V
+Landroid/graphics/PorterDuffColorFilter;->setMode(Landroid/graphics/PorterDuff$Mode;)V
 Landroid/graphics/Region;-><init>(JI)V
 Landroid/graphics/Region;->mNativeRegion:J
 Landroid/graphics/SurfaceTexture;->mFrameAvailableListener:J
@@ -694,8 +701,13 @@
 Landroid/hardware/usb/UsbManager;->setCurrentFunction(Ljava/lang/String;Z)V
 Landroid/hardware/usb/UsbManager;->setPortRoles(Landroid/hardware/usb/UsbPort;II)V
 Landroid/hardware/usb/UsbPortStatus;->getCurrentDataRole()I
+Landroid/hardware/usb/UsbPortStatus;->getCurrentMode()I
+Landroid/hardware/usb/UsbPortStatus;->getCurrentPowerRole()I
+Landroid/hardware/usb/UsbPortStatus;->getSupportedRoleCombinations()I
 Landroid/hardware/usb/UsbPortStatus;->isConnected()Z
 Landroid/hardware/usb/UsbPortStatus;->isRoleCombinationSupported(II)Z
+Landroid/hardware/usb/UsbRequest;->mBuffer:Ljava/nio/ByteBuffer;
+Landroid/hardware/usb/UsbRequest;->mLength:I
 Landroid/hardware/usb/UsbRequest;->mNativeContext:J
 Landroid/icu/impl/CurrencyData;-><init>()V
 Landroid/icu/impl/number/DecimalFormatProperties;->readObject(Ljava/io/ObjectInputStream;)V
@@ -1726,7 +1738,9 @@
 Landroid/util/NtpTrustedTime;->getCachedNtpTimeReference()J
 Landroid/util/NtpTrustedTime;->getInstance(Landroid/content/Context;)Landroid/util/NtpTrustedTime;
 Landroid/util/NtpTrustedTime;->hasCache()Z
+Landroid/util/Pools$SimplePool;->mPool:[Ljava/lang/Object;
 Landroid/util/Pools$SynchronizedPool;->acquire()Ljava/lang/Object;
+Landroid/util/Pools$SynchronizedPool;-><init>(I)V
 Landroid/util/Rational;->mDenominator:I
 Landroid/util/Rational;->mNumerator:I
 Landroid/util/Rational;->readObject(Ljava/io/ObjectInputStream;)V
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 13a6be55..83d6003 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -763,6 +763,11 @@
     public static final String CATEGORY_CALL = "call";
 
     /**
+     * Notification category: map turn-by-turn navigation.
+     */
+    public static final String CATEGORY_NAVIGATION = "navigation";
+
+    /**
      * Notification category: incoming direct message (SMS, instant message, etc.).
      */
     public static final String CATEGORY_MESSAGE = "msg";
@@ -835,6 +840,27 @@
     public static final String CATEGORY_REMINDER = "reminder";
 
     /**
+     * Notification category: extreme car emergencies.
+     * @hide
+     */
+    @SystemApi
+    public static final String CATEGORY_CAR_EMERGENCY = "car_emergency";
+
+    /**
+     * Notification category: car warnings.
+     * @hide
+     */
+    @SystemApi
+    public static final String CATEGORY_CAR_WARNING = "car_warning";
+
+    /**
+     * Notification category: general car system information.
+     * @hide
+     */
+    @SystemApi
+    public static final String CATEGORY_CAR_INFORMATION = "car_information";
+
+    /**
      * One of the predefined notification categories (see the <code>CATEGORY_*</code> constants)
      * that best describes this Notification.  May be used by the system for ranking and filtering.
      */
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index ed2aaf9..5fbe5b3 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -16,31 +16,31 @@
 
 package android.app.admin;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-import org.xmlpull.v1.XmlSerializer;
-
 import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
 import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.content.res.Resources.NotFoundException;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.PersistableBundle;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Printer;
 import android.util.SparseArray;
 import android.util.Xml;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -266,6 +266,12 @@
      */
     int mUsesPolicies;
 
+    /**
+     * Whether this administrator can be a target in an ownership transfer.
+     *
+     * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
+     */
+    boolean mSupportsTransferOwnership;
 
     /**
      * Constructor.
@@ -347,6 +353,12 @@
                                     + getComponent() + ": " + policyName);
                         }
                     }
+                } else if (tagName.equals("support-transfer-ownership")) {
+                    if (parser.next() != XmlPullParser.END_TAG) {
+                        throw new XmlPullParserException(
+                                "support-transfer-ownership tag must be empty.");
+                    }
+                    mSupportsTransferOwnership = true;
                 }
             }
         } catch (NameNotFoundException e) {
@@ -360,6 +372,7 @@
     DeviceAdminInfo(Parcel source) {
         mActivityInfo = ActivityInfo.CREATOR.createFromParcel(source);
         mUsesPolicies = source.readInt();
+        mSupportsTransferOwnership = source.readBoolean();
     }
 
     /**
@@ -458,6 +471,13 @@
         return sRevKnownPolicies.get(policyIdent).tag;
     }
 
+    /**
+     * Return true if this administrator can be a target in an ownership transfer.
+     */
+    public boolean supportsTransferOwnership() {
+        return mSupportsTransferOwnership;
+    }
+
     /** @hide */
     public ArrayList<PolicyInfo> getUsedPolicies() {
         ArrayList<PolicyInfo> res = new ArrayList<PolicyInfo>();
@@ -502,6 +522,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         mActivityInfo.writeToParcel(dest, flags);
         dest.writeInt(mUsesPolicies);
+        dest.writeBoolean(mSupportsTransferOwnership);
     }
 
     /**
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 8c30fc4..1c9477d 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -505,31 +505,6 @@
     public static final String EXTRA_TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE =
             "android.app.extra.TRANSFER_OWNERSHIP_ADMIN_EXTRAS_BUNDLE";
 
-    /**
-     * Name under which a device administration component indicates whether it supports transfer of
-     * ownership. This meta-data is of type <code>boolean</code>. A value of <code>true</code>
-     * allows this administrator to be used as a target administrator for a transfer. If the value
-     * is <code>false</code>, ownership cannot be transferred to this administrator. The default
-     * value is <code>false</code>.
-     * <p>This metadata is used to avoid ownership transfer migration to an administrator with a
-     * version which does not yet support it.
-     * <p>Usage:
-     * <pre>
-     * &lt;receiver name="..." android:permission="android.permission.BIND_DEVICE_ADMIN"&gt;
-     *     &lt;meta-data
-     *         android:name="android.app.device_admin"
-     *         android:resource="@xml/..." /&gt;
-     *     &lt;meta-data
-     *         android:name="android.app.support_transfer_ownership"
-     *         android:value="true" /&gt;
-     * &lt;/receiver&gt;
-     * </pre>
-     *
-     * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle)
-     */
-    public static final String SUPPORT_TRANSFER_OWNERSHIP_META_DATA =
-            "android.app.support_transfer_ownership";
-
     private DevicePolicyManager mManager;
     private ComponentName mWho;
 
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index d42fa99..6511f21 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -9302,9 +9302,10 @@
      * after calling this method.
      *
      * <p>The incoming target administrator must have the
-     * {@link DeviceAdminReceiver#SUPPORT_TRANSFER_OWNERSHIP_META_DATA} <code>meta-data</code> tag
-     * included in its corresponding <code>receiver</code> component with a value of {@code true}.
-     * Otherwise an {@link IllegalArgumentException} will be thrown.
+     * <code>&lt;support-transfer-ownership /&gt;</code> tag inside the
+     * <code>&lt;device-admin&gt;&lt;/device-admin&gt;</code> tags in the xml file referenced by
+     * {@link DeviceAdminReceiver#DEVICE_ADMIN_META_DATA}. Otherwise an
+     * {@link IllegalArgumentException} will be thrown.
      *
      * @param admin which {@link DeviceAdminReceiver} this request is associated with
      * @param target which {@link DeviceAdminReceiver} we want the new administrator to be
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index f7fb84b..4c7e97b 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -109,11 +109,11 @@
         public static final int NOTIFICATION_SEEN = 10;
 
         /**
-         * An event type denoting a change in App Standby Bucket. Additional bucket information
-         * is contained in mBucketAndReason.
-         * @hide
+         * An event type denoting a change in App Standby Bucket. The new bucket can be
+         * retrieved by calling {@link #getStandbyBucket()}.
+         *
+         * @see UsageStatsManager#getAppStandbyBucket()
          */
-        @SystemApi
         public static final int STANDBY_BUCKET_CHANGED = 11;
 
         /**
@@ -254,8 +254,11 @@
         /**
          * The event type.
          *
-         * See {@link #MOVE_TO_BACKGROUND}
-         * See {@link #MOVE_TO_FOREGROUND}
+         * @see #MOVE_TO_BACKGROUND
+         * @see #MOVE_TO_FOREGROUND
+         * @see #CONFIGURATION_CHANGE
+         * @see #USER_INTERACTION
+         * @see #STANDBY_BUCKET_CHANGED
          */
         public int getEventType() {
             return mEventType;
@@ -283,9 +286,8 @@
          * Returns the standby bucket of the app, if the event is of type
          * {@link #STANDBY_BUCKET_CHANGED}, otherwise returns 0.
          * @return the standby bucket associated with the event.
-         * @hide
+         *
          */
-        @SystemApi
         public int getStandbyBucket() {
             return (mBucketAndReason & 0xFFFF0000) >>> 16;
         }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index efa90d3..387a836 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -1188,7 +1188,7 @@
             if (category != CATEGORY_UNDEFINED) {
                 pw.println(prefix + "category=" + category);
             }
-            pw.println("isAllowedToUseHiddenApi=" + isAllowedToUseHiddenApi());
+            pw.println(prefix + "isAllowedToUseHiddenApi=" + isAllowedToUseHiddenApi());
         }
         super.dumpBack(pw, prefix);
     }
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 6feb170..dff51f7 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -547,4 +547,18 @@
     /** Updates the flags for the given permission. */
     public abstract void updatePermissionFlagsTEMP(@NonNull String permName,
             @NonNull String packageName, int flagMask, int flagValues, int userId);
+
+    /**
+     * Returns true if it's still safe to restore data backed up from this app's version
+     * that was signed with restoringFromSigHash.
+     */
+    public abstract boolean isDataRestoreSafe(@NonNull byte[] restoringFromSigHash,
+            @NonNull String packageName);
+
+    /**
+     * Returns true if it's still safe to restore data backed up from this app's version
+     * that was signed with restoringFromSig.
+     */
+    public abstract boolean isDataRestoreSafe(@NonNull Signature restoringFromSig,
+            @NonNull String packageName);
 }
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 5d5a978..bc7540f 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3492,7 +3492,7 @@
 
         if (sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic,
-                true)) {
+                owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.P)) {
             ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC;
         }
 
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index f468942..504f840 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -23,6 +23,7 @@
 import android.util.SparseArray;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.SurfaceControl;
 
 /**
  * Display manager local system service interface.
@@ -115,7 +116,7 @@
      * Called by the window manager to perform traversals while holding a
      * surface flinger transaction.
      */
-    public abstract void performTraversalInTransactionFromWindowManager();
+    public abstract void performTraversal(SurfaceControl.Transaction t);
 
     /**
      * Tells the display manager about properties of the display that depend on the windows on it.
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index b3bf092..b4c8a5e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -20,6 +20,8 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
 import android.annotation.CallSuper;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
@@ -239,19 +241,89 @@
     static final boolean DEBUG = false;
 
     /**
-     * The back button will close the input window.
+     * Allows the system to optimize the back button affordance based on the presence of software
+     * keyboard.
+     *
+     * <p>For instance, on devices that have navigation bar and software-rendered back button, the
+     * system may use a different icon while {@link #isInputViewShown()} returns {@code true}, to
+     * indicate that the back button has "dismiss" affordance.</p>
+     *
+     * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
+     * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
+     * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
+     * not take this mode into account.</p>
+     *
+     * <p>For API level {@link android.os.Build.VERSION_CODES#O_MR1} and lower devices, this is the
+     * only mode you can safely specify without worrying about the compatibility.</p>
+     *
+     * @see #setBackDisposition(int)
      */
-    public static final int BACK_DISPOSITION_DEFAULT = 0;  // based on window
+    public static final int BACK_DISPOSITION_DEFAULT = 0;
 
     /**
-     * This input method will not consume the back key.
+     * Deprecated flag.
+     *
+     * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
+     *
+     * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
+     *             handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
+     *             {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
+     *             of this mode had not been well defined. Most likely the end result would be the
+     *             same as {@link #BACK_DISPOSITION_DEFAULT}. Either way it is not recommended to
+     *             use this mode
+     * @see #setBackDisposition(int)
      */
-    public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1; // back
+    @Deprecated
+    public static final int BACK_DISPOSITION_WILL_NOT_DISMISS = 1;
 
     /**
-     * This input method will consume the back key.
+     * Deprecated flag.
+     *
+     * <p>To avoid compatibility issues, IME developers should not use this flag.</p>
+     *
+     * @deprecated on {@link android.os.Build.VERSION_CODES#P} and later devices, this flag is
+     *             handled as a synonym of {@link #BACK_DISPOSITION_DEFAULT}. On
+     *             {@link android.os.Build.VERSION_CODES#O_MR1} and prior devices, expected behavior
+     *             of this mode had not been well defined. In AOSP implementation running on devices
+     *             that have navigation bar, specifying this flag could change the software back
+     *             button to "Dismiss" icon no matter whether the software keyboard is shown or not,
+     *             but there would be no easy way to restore the icon state even after IME lost the
+     *             connection to the application. To avoid user confusions, do not specify this mode
+     *             anyway
+     * @see #setBackDisposition(int)
      */
-    public static final int BACK_DISPOSITION_WILL_DISMISS = 2; // down
+    @Deprecated
+    public static final int BACK_DISPOSITION_WILL_DISMISS = 2;
+
+    /**
+     * Asks the system to not adjust the back button affordance even when the software keyboard is
+     * shown.
+     *
+     * <p>This mode is useful for UI modes where IME's main soft input window is used for some
+     * supplemental UI, such as floating candidate window for languages such as Chinese and
+     * Japanese, where users expect the back button is, or at least looks to be, handled by the
+     * target application rather than the UI shown by the IME even while {@link #isInputViewShown()}
+     * returns {@code true}.</p>
+     *
+     * <p>Note that {@link KeyEvent#KEYCODE_BACK} events continue to be sent to
+     * {@link #onKeyDown(int, KeyEvent)} even when this mode is specified. The default
+     * implementation of {@link #onKeyDown(int, KeyEvent)} for {@link KeyEvent#KEYCODE_BACK} does
+     * not take this mode into account.</p>
+     *
+     * @see #setBackDisposition(int)
+     */
+    public static final int BACK_DISPOSITION_ADJUST_NOTHING = 3;
+
+    /**
+     * Enum flag to be used for {@link #setBackDisposition(int)}.
+     *
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef(value = {BACK_DISPOSITION_DEFAULT, BACK_DISPOSITION_WILL_NOT_DISMISS,
+            BACK_DISPOSITION_WILL_DISMISS, BACK_DISPOSITION_ADJUST_NOTHING},
+            prefix = "BACK_DISPOSITION_")
+    public @interface BackDispositionMode {}
 
     /**
      * @hide
@@ -267,7 +339,7 @@
 
     // Min and max values for back disposition.
     private static final int BACK_DISPOSITION_MIN = BACK_DISPOSITION_DEFAULT;
-    private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_WILL_DISMISS;
+    private static final int BACK_DISPOSITION_MAX = BACK_DISPOSITION_ADJUST_NOTHING;
 
     InputMethodManager mImm;
     
@@ -331,6 +403,8 @@
     boolean mIsInputViewShown;
     
     int mStatusIcon;
+
+    @BackDispositionMode
     int mBackDisposition;
 
     /**
@@ -1015,8 +1089,19 @@
     public Dialog getWindow() {
         return mWindow;
     }
-    
-    public void setBackDisposition(int disposition) {
+
+    /**
+     * Sets the disposition mode that indicates the expected affordance for the back button.
+     *
+     * <p>Keep in mind that specifying this flag does not change the the default behavior of
+     * {@link #onKeyDown(int, KeyEvent)}.  It is IME developers' responsibility for making sure that
+     * their custom implementation of {@link #onKeyDown(int, KeyEvent)} is consistent with the mode
+     * specified to this API.</p>
+     *
+     * @see #getBackDisposition()
+     * @param disposition disposition mode to be set
+     */
+    public void setBackDisposition(@BackDispositionMode int disposition) {
         if (disposition == mBackDisposition) {
             return;
         }
@@ -1029,6 +1114,13 @@
                 mBackDisposition);
     }
 
+    /**
+     * Retrieves the current disposition mode that indicates the expected back button affordance.
+     *
+     * @see #setBackDisposition(int)
+     * @return currently selected disposition mode
+     */
+    @BackDispositionMode
     public int getBackDisposition() {
         return mBackDisposition;
     }
@@ -1894,7 +1986,6 @@
         mInputStarted = false;
         mStartedInputConnection = null;
         mCurCompletions = null;
-        mBackDisposition = BACK_DISPOSITION_DEFAULT;
     }
 
     void doStartInput(InputConnection ic, EditorInfo attribute, boolean restarting) {
@@ -2096,25 +2187,31 @@
         return mExtractEditText;
     }
 
+
     /**
-     * Override this to intercept key down events before they are processed by the
-     * application.  If you return true, the application will not 
-     * process the event itself.  If you return false, the normal application processing
-     * will occur as if the IME had not seen the event at all.
-     * 
-     * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK
-     * KeyEvent.KEYCODE_BACK} if the IME is currently shown, to
-     * possibly hide it when the key goes up (if not canceled or long pressed).  In
-     * addition, in fullscreen mode only, it will consume DPAD movement
-     * events to move the cursor in the extracted text view, not allowing
-     * them to perform navigation in the underlying application.
+     * Called back when a {@link KeyEvent} is forwarded from the target application.
+     *
+     * <p>The default implementation intercepts {@link KeyEvent#KEYCODE_BACK} if the IME is
+     * currently shown , to possibly hide it when the key goes up (if not canceled or long pressed).
+     * In addition, in fullscreen mode only, it will consume DPAD movement events to move the cursor
+     * in the extracted text view, not allowing them to perform navigation in the underlying
+     * application.</p>
+     *
+     * <p>The default implementation does not take flags specified to
+     * {@link #setBackDisposition(int)} into account, even on API version
+     * {@link android.os.Build.VERSION_CODES#P} and later devices.  IME developers are responsible
+     * for making sure that their special handling for {@link KeyEvent#KEYCODE_BACK} are consistent
+     * with the flag they specified to {@link #setBackDisposition(int)}.</p>
+     *
+     * @param keyCode The value in {@code event.getKeyCode()}
+     * @param event Description of the key event
+     *
+     * @return {@code true} if the event is consumed by the IME and the application no longer needs
+     *         to consume it.  Return {@code false} when the event should be handled as if the IME
+     *         had not seen the event at all.
      */
     public boolean onKeyDown(int keyCode, KeyEvent event) {
-
         if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
-            if (mBackDisposition == BACK_DISPOSITION_WILL_NOT_DISMISS) {
-                return false;
-            }
             final ExtractEditText eet = getExtractEditTextIfVisible();
             if (eet != null && eet.handleBackInTextActionModeIfNeeded(event)) {
                 return true;
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index 2bb43bd..e84f913 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -103,7 +103,7 @@
      * @hide // TODO Expose in the future?  Too late for O.
      */
     public LogMaker setLatency(long milliseconds) {
-        entries.put(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS, milliseconds);
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS, milliseconds);
         return this;
     }
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 60f7295..2b5cece 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -10378,6 +10378,17 @@
         public static final String SYS_UIDCPUPOWER = "sys_uidcpupower";
 
         /**
+        * traced global setting. This controls weather the deamons: traced and
+        * traced_probes run. This links the sys.traced system property.
+        * The following values are supported:
+        * 0 -> traced and traced_probes are disabled
+        * 1 -> traced and traced_probes are enabled
+        * Any other value defaults to disabled.
+        * @hide
+        */
+        public static final String SYS_TRACED = "sys_traced";
+
+        /**
          * An integer to reduce the FPS by this factor. Only for experiments. Need to reboot the
          * device for this setting to take full effect.
          *
diff --git a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java b/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
deleted file mode 100644
index 4275c29..0000000
--- a/core/java/android/security/keystore/recovery/BadCertificateFormatException.java
+++ /dev/null
@@ -1,27 +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 android.security.keystore.recovery;
-
-/**
- * @deprecated Not used.
- * @hide
- */
-public class BadCertificateFormatException extends RecoveryControllerException {
-    public BadCertificateFormatException(String msg) {
-        super(msg);
-    }
-}
diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
index 4580c47..00f54e1 100644
--- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
+++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java
@@ -18,12 +18,14 @@
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.os.BadParcelableException;
 import android.os.Parcel;
 import android.os.Parcelable;
 
 import com.android.internal.util.Preconditions;
 
 import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
 import java.util.List;
 
 /**
@@ -54,7 +56,7 @@
     private long mCounterId = DEFAULT_COUNTER_ID;
     private byte[] mServerParams;
     private byte[] mPublicKey;  // The raw public key bytes used
-    private CertPath mCertPath;  // The certificate path including the intermediate certificates
+    private RecoveryCertPath mCertPath;  // The cert path including necessary intermediate certs
     private List<KeyChainProtectionParams> mKeyChainProtectionParams;
     private List<WrappedApplicationKey> mEntryRecoveryData;
     private byte[] mEncryptedRecoveryKeyBlob;
@@ -127,7 +129,17 @@
      */
     // TODO: Change to @NonNull
     public CertPath getTrustedHardwareCertPath() {
-        return mCertPath;
+        if (mCertPath == null) {
+            return null;
+        } else {
+            try {
+                return mCertPath.getCertPath();
+            } catch (CertificateException e) {
+                // Rethrow an unchecked exception as it should not happen. If such an issue exists,
+                // an exception should have been thrown during service initialization.
+                throw new BadParcelableException(e);
+            }
+        }
     }
 
     /**
@@ -232,11 +244,17 @@
          * contain a certificate of the trusted hardware public key and any necessary intermediate
          * certificates.
          *
-         * @param certPath The public key
+         * @param certPath The certificate path
+         * @throws CertificateException if the given certificate path cannot be encoded properly
          * @return This builder.
          */
-        public Builder setTrustedHardwareCertPath(CertPath certPath) {
-            mInstance.mCertPath = certPath;
+        public Builder setTrustedHardwareCertPath(CertPath certPath) throws CertificateException {
+            // TODO: Make it NonNull when the caller code is all updated
+            if (certPath == null) {
+                mInstance.mCertPath = null;
+            } else {
+                mInstance.mCertPath = RecoveryCertPath.createRecoveryCertPath(certPath);
+            }
             return this;
         }
 
@@ -302,6 +320,7 @@
         out.writeLong(mCounterId);
         out.writeByteArray(mServerParams);
         out.writeByteArray(mPublicKey);
+        out.writeTypedObject(mCertPath, /* no flags */ 0);
     }
 
     /**
@@ -316,6 +335,7 @@
         mCounterId = in.readLong();
         mServerParams = in.createByteArray();
         mPublicKey = in.createByteArray();
+        mCertPath = in.readTypedObject(RecoveryCertPath.CREATOR);
     }
 
     @Override
diff --git a/core/java/android/security/keystore/recovery/RecoveryControllerException.java b/core/java/android/security/keystore/recovery/RecoveryControllerException.java
deleted file mode 100644
index 1af61ce..0000000
--- a/core/java/android/security/keystore/recovery/RecoveryControllerException.java
+++ /dev/null
@@ -1,35 +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 android.security.keystore.recovery;
-
-import java.security.GeneralSecurityException;
-
-/**
- * @deprecated Not used.
- * @hide
- */
-public abstract class RecoveryControllerException extends GeneralSecurityException {
-    RecoveryControllerException() { }
-
-    RecoveryControllerException(String msg) {
-        super(msg);
-    }
-
-    public RecoveryControllerException(String message, Throwable cause) {
-        super(message, cause);
-    }
-}
diff --git a/core/java/android/view/RecordingCanvas.java b/core/java/android/view/RecordingCanvas.java
index fc7d828..f7a41ff 100644
--- a/core/java/android/view/RecordingCanvas.java
+++ b/core/java/android/view/RecordingCanvas.java
@@ -474,8 +474,7 @@
         }
 
         nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
-                x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */,
-                0 /* measured text offset */);
+                x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
     }
 
     @Override
@@ -506,19 +505,16 @@
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             long measuredTextPtr = 0;
-            int measuredTextOffset = 0;
             if (text instanceof PrecomputedText) {
                 PrecomputedText mt = (PrecomputedText) text;
                 int paraIndex = mt.findParaIndex(start);
                 if (end <= mt.getParagraphEnd(paraIndex)) {
                     // Only support if the target is in the same paragraph.
                     measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr();
-                    measuredTextOffset = start - mt.getParagraphStart(paraIndex);
                 }
             }
             nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
-                    0, contextLen, x, y, isRtl, paint.getNativeInstance(),
-                    measuredTextPtr, measuredTextOffset);
+                    0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -641,7 +637,7 @@
     @FastNative
     private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
             int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
-            long nativePrecomputedText, int measuredTextOffset);
+            long nativePrecomputedText);
 
     @FastNative
     private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index f39b73e..5178a97 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -251,7 +251,7 @@
  * density, or high density screens, respectively. For example:
  * <pre>
  * &lt;link rel="stylesheet" media="screen and (-webkit-device-pixel-ratio:1.5)" href="hdpi.css" /&gt;</pre>
- * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ration of 1.5,
+ * <p>The {@code hdpi.css} stylesheet is only used for devices with a screen pixel ratio of 1.5,
  * which is the high density pixel ratio.
  * </li>
  * </ul>
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index 75fc538..bbdf15c 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -1182,12 +1182,12 @@
      * determine where to position the view on the screen.  If the view is not contained
      * within a relative layout, these attributes are ignored.
      *
-     * See the <a href=“https://developer.android.com/guide/topics/ui/layout/relative.html”>
+     * See the <a href="/guide/topics/ui/layout/relative.html">
      * Relative Layout</a> guide for example code demonstrating how to use relative layout’s
      * layout parameters in a layout XML.
      *
      * To learn more about layout parameters and how they differ from typical view attributes,
-     * see the <a href=“https://developer.android.com/guide/topics/ui/declaring-layout.html#attributes”>
+     * see the <a href="/guide/topics/ui/declaring-layout.html#attributes">
      *     Layouts guide</a>.
      *
      *
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 2c05d0b..bd14d453 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -309,7 +309,7 @@
             jint count, jint bidiFlags, jfloat x, jfloat y, SkPath* path) {
         minikin::Layout layout = MinikinUtils::doLayout(
                 paint, static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count,
-                nullptr, 0);
+                nullptr);
         size_t nGlyphs = layout.nGlyphs();
         uint16_t* glyphs = new uint16_t[nGlyphs];
         SkPoint* pos = new SkPoint[nGlyphs];
@@ -351,8 +351,7 @@
         SkIRect ir;
 
         minikin::Layout layout = MinikinUtils::doLayout(&paint,
-                static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, nullptr,
-                0);
+                static_cast<minikin::Bidi>(bidiFlags), typeface, text, 0, count, count, nullptr);
         minikin::MinikinRect rect;
         layout.getBounds(&rect);
         r.fLeft = rect.mLeft;
@@ -468,7 +467,7 @@
         }
         minikin::Layout layout = MinikinUtils::doLayout(paint,
                 static_cast<minikin::Bidi>(bidiFlags), typeface, str.get(), 0, str.size(),
-                str.size(), nullptr, 0);
+                str.size(), nullptr);
         size_t nGlyphs = countNonSpaceGlyphs(layout);
         if (nGlyphs != 1 && nChars > 1) {
             // multiple-character input, and was not a ligature
@@ -489,7 +488,7 @@
             static const jchar ZZ_FLAG_STR[] = { 0xD83C, 0xDDFF, 0xD83C, 0xDDFF };
             minikin::Layout zzLayout = MinikinUtils::doLayout(paint,
                     static_cast<minikin::Bidi>(bidiFlags), typeface, ZZ_FLAG_STR, 0, 4, 4,
-                    nullptr, 0);
+                    nullptr);
             if (zzLayout.nGlyphs() != 1 || layoutContainsNotdef(zzLayout)) {
                 // The font collection doesn't have a glyph for unknown flag. Just return true.
                 return true;
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 06de5da..0017f6c 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -484,7 +484,7 @@
     const Typeface* typeface = paint->getAndroidTypeface();
     jchar* jchars = env->GetCharArrayElements(text, NULL);
     get_canvas(canvasHandle)->drawText(jchars + index, 0, count, count, x, y,
-            static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr, 0);
+            static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr);
     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
 }
 
@@ -496,13 +496,13 @@
     const int count = end - start;
     const jchar* jchars = env->GetStringChars(text, NULL);
     get_canvas(canvasHandle)->drawText(jchars + start, 0, count, count, x, y,
-            static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr, 0);
+            static_cast<minikin::Bidi>(bidiFlags), *paint, typeface, nullptr);
     env->ReleaseStringChars(text, jchars);
 }
 
 static void drawTextRunChars(JNIEnv* env, jobject, jlong canvasHandle, jcharArray text, jint index,
                              jint count, jint contextIndex, jint contextCount, jfloat x, jfloat y,
-                             jboolean isRtl, jlong paintHandle, jlong mtHandle, jint mtOffset) {
+                             jboolean isRtl, jlong paintHandle, jlong mtHandle) {
     Paint* paint = reinterpret_cast<Paint*>(paintHandle);
     minikin::MeasuredText* mt = reinterpret_cast<minikin::MeasuredText*>(mtHandle);
     const Typeface* typeface = paint->getAndroidTypeface();
@@ -510,8 +510,7 @@
     const minikin::Bidi bidiFlags = isRtl ? minikin::Bidi::FORCE_RTL : minikin::Bidi::FORCE_LTR;
     jchar* jchars = env->GetCharArrayElements(text, NULL);
     get_canvas(canvasHandle)->drawText(jchars + contextIndex, index - contextIndex, count,
-                                       contextCount, x, y, bidiFlags, *paint, typeface, mt,
-                                       mtOffset);
+                                       contextCount, x, y, bidiFlags, *paint, typeface, mt);
     env->ReleaseCharArrayElements(text, jchars, JNI_ABORT);
 }
 
@@ -526,7 +525,7 @@
     jint contextCount = contextEnd - contextStart;
     const jchar* jchars = env->GetStringChars(text, NULL);
     get_canvas(canvasHandle)->drawText(jchars + contextStart, start - contextStart, count,
-                                       contextCount, x, y, bidiFlags, *paint, typeface, nullptr, 0);
+                                       contextCount, x, y, bidiFlags, *paint, typeface, nullptr);
     env->ReleaseStringChars(text, jchars);
 }
 
@@ -640,7 +639,7 @@
     {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
     {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars},
     {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString},
-    {"nDrawTextRun","(J[CIIIIFFZJJI)V", (void*) CanvasJNI::drawTextRunChars},
+    {"nDrawTextRun","(J[CIIIIFFZJJ)V", (void*) CanvasJNI::drawTextRunChars},
     {"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
     {"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
     {"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index d05be2c..7c8a52d 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -71,6 +71,9 @@
 using android::base::StringPrintf;
 using android::base::WriteStringToFile;
 
+#define CREATE_ERROR(...) StringPrintf("%s:%d: ", __FILE__, __LINE__). \
+                              append(StringPrintf(__VA_ARGS__))
+
 static pid_t gSystemServerPid = 0;
 
 static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
@@ -186,30 +189,32 @@
 
 // Calls POSIX setgroups() using the int[] object as an argument.
 // A NULL argument is tolerated.
-static void SetGids(JNIEnv* env, jintArray javaGids) {
+static bool SetGids(JNIEnv* env, jintArray javaGids, std::string* error_msg) {
   if (javaGids == NULL) {
-    return;
+    return true;
   }
 
   ScopedIntArrayRO gids(env, javaGids);
   if (gids.get() == NULL) {
-    RuntimeAbort(env, __LINE__, "Getting gids int array failed");
+    *error_msg = CREATE_ERROR("Getting gids int array failed");
+    return false;
   }
   int rc = setgroups(gids.size(), reinterpret_cast<const gid_t*>(&gids[0]));
   if (rc == -1) {
-    std::ostringstream oss;
-    oss << "setgroups failed: " << strerror(errno) << ", gids.size=" << gids.size();
-    RuntimeAbort(env, __LINE__, oss.str().c_str());
+    *error_msg = CREATE_ERROR("setgroups failed: %s, gids.size=%zu", strerror(errno), gids.size());
+    return false;
   }
+
+  return true;
 }
 
 // Sets the resource limits via setrlimit(2) for the values in the
 // two-dimensional array of integers that's passed in. The second dimension
 // contains a tuple of length 3: (resource, rlim_cur, rlim_max). NULL is
 // treated as an empty array.
-static void SetRLimits(JNIEnv* env, jobjectArray javaRlimits) {
+static bool SetRLimits(JNIEnv* env, jobjectArray javaRlimits, std::string* error_msg) {
   if (javaRlimits == NULL) {
-    return;
+    return true;
   }
 
   rlimit rlim;
@@ -219,7 +224,8 @@
     ScopedLocalRef<jobject> javaRlimitObject(env, env->GetObjectArrayElement(javaRlimits, i));
     ScopedIntArrayRO javaRlimit(env, reinterpret_cast<jintArray>(javaRlimitObject.get()));
     if (javaRlimit.size() != 3) {
-      RuntimeAbort(env, __LINE__, "rlimits array must have a second dimension of size 3");
+      *error_msg = CREATE_ERROR("rlimits array must have a second dimension of size 3");
+      return false;
     }
 
     rlim.rlim_cur = javaRlimit[1];
@@ -227,11 +233,13 @@
 
     int rc = setrlimit(javaRlimit[0], &rlim);
     if (rc == -1) {
-      ALOGE("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur,
+      *error_msg = CREATE_ERROR("setrlimit(%d, {%ld, %ld}) failed", javaRlimit[0], rlim.rlim_cur,
             rlim.rlim_max);
-      RuntimeAbort(env, __LINE__, "setrlimit failed");
+      return false;
     }
   }
+
+  return true;
 }
 
 // The debug malloc library needs to know whether it's the zygote or a child.
@@ -259,14 +267,16 @@
   }
 }
 
-static void EnableKeepCapabilities(JNIEnv* env) {
+static bool EnableKeepCapabilities(std::string* error_msg) {
   int rc = prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
   if (rc == -1) {
-    RuntimeAbort(env, __LINE__, "prctl(PR_SET_KEEPCAPS) failed");
+    *error_msg = CREATE_ERROR("prctl(PR_SET_KEEPCAPS) failed: %s", strerror(errno));
+    return false;
   }
+  return true;
 }
 
-static void DropCapabilitiesBoundingSet(JNIEnv* env) {
+static bool DropCapabilitiesBoundingSet(std::string* error_msg) {
   for (int i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0; i++) {
     int rc = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
     if (rc == -1) {
@@ -274,14 +284,15 @@
         ALOGE("prctl(PR_CAPBSET_DROP) failed with EINVAL. Please verify "
               "your kernel is compiled with file capabilities support");
       } else {
-        ALOGE("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
-        RuntimeAbort(env, __LINE__, "prctl(PR_CAPBSET_DROP) failed");
+        *error_msg = CREATE_ERROR("prctl(PR_CAPBSET_DROP, %d) failed: %s", i, strerror(errno));
+        return false;
       }
     }
   }
+  return true;
 }
 
-static void SetInheritable(JNIEnv* env, uint64_t inheritable) {
+static bool SetInheritable(uint64_t inheritable, std::string* error_msg) {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
   capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -289,21 +300,23 @@
 
   __user_cap_data_struct capdata[2];
   if (capget(&capheader, &capdata[0]) == -1) {
-    ALOGE("capget failed: %s", strerror(errno));
-    RuntimeAbort(env, __LINE__, "capget failed");
+    *error_msg = CREATE_ERROR("capget failed: %s", strerror(errno));
+    return false;
   }
 
   capdata[0].inheritable = inheritable;
   capdata[1].inheritable = inheritable >> 32;
 
   if (capset(&capheader, &capdata[0]) == -1) {
-    ALOGE("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
-    RuntimeAbort(env, __LINE__, "capset failed");
+    *error_msg = CREATE_ERROR("capset(inh=%" PRIx64 ") failed: %s", inheritable, strerror(errno));
+    return false;
   }
+
+  return true;
 }
 
-static void SetCapabilities(JNIEnv* env, uint64_t permitted, uint64_t effective,
-                            uint64_t inheritable) {
+static bool SetCapabilities(uint64_t permitted, uint64_t effective, uint64_t inheritable,
+                            std::string* error_msg) {
   __user_cap_header_struct capheader;
   memset(&capheader, 0, sizeof(capheader));
   capheader.version = _LINUX_CAPABILITY_VERSION_3;
@@ -319,18 +332,20 @@
   capdata[1].inheritable = inheritable >> 32;
 
   if (capset(&capheader, &capdata[0]) == -1) {
-    ALOGE("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") failed: %s", permitted,
-          effective, inheritable, strerror(errno));
-    RuntimeAbort(env, __LINE__, "capset failed");
+    *error_msg = CREATE_ERROR("capset(perm=%" PRIx64 ", eff=%" PRIx64 ", inh=%" PRIx64 ") "
+                              "failed: %s", permitted, effective, inheritable, strerror(errno));
+    return false;
   }
+  return true;
 }
 
-static void SetSchedulerPolicy(JNIEnv* env) {
+static bool SetSchedulerPolicy(std::string* error_msg) {
   errno = -set_sched_policy(0, SP_DEFAULT);
   if (errno != 0) {
-    ALOGE("set_sched_policy(0, SP_DEFAULT) failed");
-    RuntimeAbort(env, __LINE__, "set_sched_policy(0, SP_DEFAULT) failed");
+    *error_msg = CREATE_ERROR("set_sched_policy(0, SP_DEFAULT) failed: %s", strerror(errno));
+    return false;
   }
+  return true;
 }
 
 static int UnmountTree(const char* path) {
@@ -364,7 +379,7 @@
 // Create a private mount namespace and bind mount appropriate emulated
 // storage for the given user.
 static bool MountEmulatedStorage(uid_t uid, jint mount_mode,
-        bool force_mount_namespace) {
+        bool force_mount_namespace, std::string* error_msg) {
     // See storage config details at http://source.android.com/tech/storage/
 
     String8 storageSource;
@@ -381,7 +396,7 @@
 
     // Create a second private mount namespace for our process
     if (unshare(CLONE_NEWNS) == -1) {
-        ALOGW("Failed to unshare(): %s", strerror(errno));
+        *error_msg = CREATE_ERROR("Failed to unshare(): %s", strerror(errno));
         return false;
     }
 
@@ -392,7 +407,9 @@
 
     if (TEMP_FAILURE_RETRY(mount(storageSource.string(), "/storage",
             NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
-        ALOGW("Failed to mount %s to /storage: %s", storageSource.string(), strerror(errno));
+        *error_msg = CREATE_ERROR("Failed to mount %s to /storage: %s",
+                                  storageSource.string(),
+                                  strerror(errno));
         return false;
     }
 
@@ -400,11 +417,14 @@
     userid_t user_id = multiuser_get_user_id(uid);
     const String8 userSource(String8::format("/mnt/user/%d", user_id));
     if (fs_prepare_dir(userSource.string(), 0751, 0, 0) == -1) {
+        *error_msg = CREATE_ERROR("fs_prepare_dir failed on %s", userSource.string());
         return false;
     }
     if (TEMP_FAILURE_RETRY(mount(userSource.string(), "/storage/self",
             NULL, MS_BIND, NULL)) == -1) {
-        ALOGW("Failed to mount %s to /storage/self: %s", userSource.string(), strerror(errno));
+        *error_msg = CREATE_ERROR("Failed to mount %s to /storage/self: %s",
+                                  userSource.string(),
+                                  strerror(errno));
         return false;
     }
 
@@ -436,31 +456,32 @@
 // descriptor (if any) is closed via dup2(), replacing it with a valid
 // (open) descriptor to /dev/null.
 
-static void DetachDescriptors(JNIEnv* env, jintArray fdsToClose) {
+static bool DetachDescriptors(JNIEnv* env, jintArray fdsToClose, std::string* error_msg) {
   if (!fdsToClose) {
-    return;
+    return true;
   }
   jsize count = env->GetArrayLength(fdsToClose);
   ScopedIntArrayRO ar(env, fdsToClose);
   if (ar.get() == NULL) {
-      RuntimeAbort(env, __LINE__, "Bad fd array");
+    *error_msg = "Bad fd array";
+    return false;
   }
   jsize i;
   int devnull;
   for (i = 0; i < count; i++) {
     devnull = open("/dev/null", O_RDWR);
     if (devnull < 0) {
-      ALOGE("Failed to open /dev/null: %s", strerror(errno));
-      RuntimeAbort(env, __LINE__, "Failed to open /dev/null");
-      continue;
+      *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
+      return false;
     }
     ALOGV("Switching descriptor %d to /dev/null: %s", ar[i], strerror(errno));
     if (dup2(devnull, ar[i]) < 0) {
-      ALOGE("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno));
-      RuntimeAbort(env, __LINE__, "Failed dup2()");
+      *error_msg = StringPrintf("Failed dup2() on descriptor %d: %s", ar[i], strerror(errno));
+      return false;
     }
     close(devnull);
   }
+  return true;
 }
 
 void SetThreadName(const char* thread_name) {
@@ -495,20 +516,23 @@
 // The list of open zygote file descriptors.
 static FileDescriptorTable* gOpenFdTable = NULL;
 
-static void FillFileDescriptorVector(JNIEnv* env,
+static bool FillFileDescriptorVector(JNIEnv* env,
                                      jintArray java_fds,
-                                     std::vector<int>* fds) {
+                                     std::vector<int>* fds,
+                                     std::string* error_msg) {
   CHECK(fds != nullptr);
   if (java_fds != nullptr) {
     ScopedIntArrayRO ar(env, java_fds);
     if (ar.get() == nullptr) {
-      RuntimeAbort(env, __LINE__, "Bad fd array");
+      *error_msg = "Bad fd array";
+      return false;
     }
     fds->reserve(ar.size());
     for (size_t i = 0; i < ar.size(); ++i) {
       fds->push_back(ar[i]);
     }
   }
+  return true;
 }
 
 // Utility routine to fork zygote and specialize the child process.
@@ -526,32 +550,53 @@
   sigemptyset(&sigchld);
   sigaddset(&sigchld, SIGCHLD);
 
+  auto fail_fn = [env, java_se_name, is_system_server](const std::string& msg)
+      __attribute__ ((noreturn)) {
+    const char* se_name_c_str = nullptr;
+    std::unique_ptr<ScopedUtfChars> se_name;
+    if (java_se_name != nullptr) {
+      se_name.reset(new ScopedUtfChars(env, java_se_name));
+      se_name_c_str = se_name->c_str();
+    }
+    if (se_name_c_str == nullptr && is_system_server) {
+      se_name_c_str = "system_server";
+    }
+    const std::string& error_msg = (se_name_c_str == nullptr)
+        ? msg
+        : StringPrintf("(%s) %s", se_name_c_str, msg.c_str());
+    env->FatalError(error_msg.c_str());
+    __builtin_unreachable();
+  };
+
   // Temporarily block SIGCHLD during forks. The SIGCHLD handler might
   // log, which would result in the logging FDs we close being reopened.
   // This would cause failures because the FDs are not whitelisted.
   //
   // Note that the zygote process is single threaded at this point.
   if (sigprocmask(SIG_BLOCK, &sigchld, nullptr) == -1) {
-    ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
-    RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_BLOCK, { SIGCHLD }) failed.");
+    fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
   }
 
   // Close any logging related FDs before we start evaluating the list of
   // file descriptors.
   __android_log_close();
 
+  std::string error_msg;
+
   // If this is the first fork for this zygote, create the open FD table.
   // If it isn't, we just need to check whether the list of open files has
   // changed (and it shouldn't in the normal case).
   std::vector<int> fds_to_ignore;
-  FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore);
+  if (!FillFileDescriptorVector(env, fdsToIgnore, &fds_to_ignore, &error_msg)) {
+    fail_fn(error_msg);
+  }
   if (gOpenFdTable == NULL) {
-    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore);
+    gOpenFdTable = FileDescriptorTable::Create(fds_to_ignore, &error_msg);
     if (gOpenFdTable == NULL) {
-      RuntimeAbort(env, __LINE__, "Unable to construct file descriptor table.");
+      fail_fn(error_msg);
     }
-  } else if (!gOpenFdTable->Restat(fds_to_ignore)) {
-    RuntimeAbort(env, __LINE__, "Unable to restat file descriptor table.");
+  } else if (!gOpenFdTable->Restat(fds_to_ignore, &error_msg)) {
+    fail_fn(error_msg);
   }
 
   pid_t pid = fork();
@@ -560,17 +605,18 @@
     PreApplicationInit();
 
     // Clean up any descriptors which must be closed immediately
-    DetachDescriptors(env, fdsToClose);
+    if (!DetachDescriptors(env, fdsToClose, &error_msg)) {
+      fail_fn(error_msg);
+    }
 
     // Re-open all remaining open file descriptors so that they aren't shared
     // with the zygote across a fork.
-    if (!gOpenFdTable->ReopenOrDetach()) {
-      RuntimeAbort(env, __LINE__, "Unable to reopen whitelisted descriptors.");
+    if (!gOpenFdTable->ReopenOrDetach(&error_msg)) {
+      fail_fn(error_msg);
     }
 
     if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
-      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
-      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+      fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
     }
 
     // Must be called when the new process still has CAP_SYS_ADMIN.  The other alternative is to
@@ -580,11 +626,17 @@
 
     // Keep capabilities across UID change, unless we're staying root.
     if (uid != 0) {
-      EnableKeepCapabilities(env);
+      if (!EnableKeepCapabilities(&error_msg)) {
+        fail_fn(error_msg);
+      }
     }
 
-    SetInheritable(env, permittedCapabilities);
-    DropCapabilitiesBoundingSet(env);
+    if (!SetInheritable(permittedCapabilities, &error_msg)) {
+      fail_fn(error_msg);
+    }
+    if (!DropCapabilitiesBoundingSet(&error_msg)) {
+      fail_fn(error_msg);
+    }
 
     bool use_native_bridge = !is_system_server && (instructionSet != NULL)
         && android::NativeBridgeAvailable();
@@ -601,8 +653,8 @@
       ALOGW("Native bridge will not be used because dataDir == NULL.");
     }
 
-    if (!MountEmulatedStorage(uid, mount_external, use_native_bridge)) {
-      ALOGW("Failed to mount emulated storage: %s", strerror(errno));
+    if (!MountEmulatedStorage(uid, mount_external, use_native_bridge, &error_msg)) {
+      ALOGW("Failed to mount emulated storage: %s (%s)", error_msg.c_str(), strerror(errno));
       if (errno == ENOTCONN || errno == EROFS) {
         // When device is actively encrypting, we get ENOTCONN here
         // since FUSE was mounted before the framework restarted.
@@ -610,7 +662,7 @@
         // FUSE hasn't been created yet by init.
         // In either case, continue without external storage.
       } else {
-        RuntimeAbort(env, __LINE__, "Cannot continue without emulated storage");
+        fail_fn(error_msg);
       }
     }
 
@@ -625,9 +677,14 @@
         }
     }
 
-    SetGids(env, javaGids);
+    std::string error_msg;
+    if (!SetGids(env, javaGids, &error_msg)) {
+      fail_fn(error_msg);
+    }
 
-    SetRLimits(env, javaRlimits);
+    if (!SetRLimits(env, javaRlimits, &error_msg)) {
+      fail_fn(error_msg);
+    }
 
     if (use_native_bridge) {
       ScopedUtfChars isa_string(env, instructionSet);
@@ -637,14 +694,12 @@
 
     int rc = setresgid(gid, gid, gid);
     if (rc == -1) {
-      ALOGE("setresgid(%d) failed: %s", gid, strerror(errno));
-      RuntimeAbort(env, __LINE__, "setresgid failed");
+      fail_fn(CREATE_ERROR("setresgid(%d) failed: %s", gid, strerror(errno)));
     }
 
     rc = setresuid(uid, uid, uid);
     if (rc == -1) {
-      ALOGE("setresuid(%d) failed: %s", uid, strerror(errno));
-      RuntimeAbort(env, __LINE__, "setresuid failed");
+      fail_fn(CREATE_ERROR("setresuid(%d) failed: %s", uid, strerror(errno)));
     }
 
     if (NeedsNoRandomizeWorkaround()) {
@@ -656,9 +711,14 @@
         }
     }
 
-    SetCapabilities(env, permittedCapabilities, effectiveCapabilities, permittedCapabilities);
+    if (!SetCapabilities(permittedCapabilities, effectiveCapabilities, permittedCapabilities,
+                         &error_msg)) {
+      fail_fn(error_msg);
+    }
 
-    SetSchedulerPolicy(env);
+    if (!SetSchedulerPolicy(&error_msg)) {
+      fail_fn(error_msg);
+    }
 
     const char* se_info_c_str = NULL;
     ScopedUtfChars* se_info = NULL;
@@ -666,7 +726,7 @@
         se_info = new ScopedUtfChars(env, java_se_info);
         se_info_c_str = se_info->c_str();
         if (se_info_c_str == NULL) {
-          RuntimeAbort(env, __LINE__, "se_info_c_str == NULL");
+          fail_fn("se_info_c_str == NULL");
         }
     }
     const char* se_name_c_str = NULL;
@@ -675,14 +735,13 @@
         se_name = new ScopedUtfChars(env, java_se_name);
         se_name_c_str = se_name->c_str();
         if (se_name_c_str == NULL) {
-          RuntimeAbort(env, __LINE__, "se_name_c_str == NULL");
+          fail_fn("se_name_c_str == NULL");
         }
     }
     rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
     if (rc == -1) {
-      ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
-            is_system_server, se_info_c_str, se_name_c_str);
-      RuntimeAbort(env, __LINE__, "selinux_android_setcontext failed");
+      fail_fn(CREATE_ERROR("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+            is_system_server, se_info_c_str, se_name_c_str));
     }
 
     // Make it easier to debug audit logs by setting the main thread's name to the
@@ -703,15 +762,14 @@
     env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, runtime_flags,
                               is_system_server, is_child_zygote, instructionSet);
     if (env->ExceptionCheck()) {
-      RuntimeAbort(env, __LINE__, "Error calling post fork hooks.");
+      fail_fn("Error calling post fork hooks.");
     }
   } else if (pid > 0) {
     // the parent process
 
     // We blocked SIGCHLD prior to a fork, we unblock it here.
     if (sigprocmask(SIG_UNBLOCK, &sigchld, nullptr) == -1) {
-      ALOGE("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno));
-      RuntimeAbort(env, __LINE__, "Call to sigprocmask(SIG_UNBLOCK, { SIGCHLD }) failed.");
+      fail_fn(CREATE_ERROR("sigprocmask(SIG_SETMASK, { SIGCHLD }) failed: %s", strerror(errno)));
     }
   }
   return pid;
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 2e60582..c5904e0 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -123,14 +123,57 @@
 
 FileDescriptorWhitelist* FileDescriptorWhitelist::instance_ = nullptr;
 
+// Keeps track of all relevant information (flags, offset etc.) of an
+// open zygote file descriptor.
+class FileDescriptorInfo {
+ public:
+  // Create a FileDescriptorInfo for a given file descriptor. Returns
+  // |NULL| if an error occurred.
+  static FileDescriptorInfo* CreateFromFd(int fd, std::string* error_msg);
+
+  // Checks whether the file descriptor associated with this object
+  // refers to the same description.
+  bool Restat() const;
+
+  bool ReopenOrDetach(std::string* error_msg) const;
+
+  const int fd;
+  const struct stat stat;
+  const std::string file_path;
+  const int open_flags;
+  const int fd_flags;
+  const int fs_flags;
+  const off_t offset;
+  const bool is_sock;
+
+ private:
+  FileDescriptorInfo(int fd);
+
+  FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
+                     int fd_flags, int fs_flags, off_t offset);
+
+  // Returns the locally-bound name of the socket |fd|. Returns true
+  // iff. all of the following hold :
+  //
+  // - the socket's sa_family is AF_UNIX.
+  // - the length of the path is greater than zero (i.e, not an unnamed socket).
+  // - the first byte of the path isn't zero (i.e, not a socket with an abstract
+  //   address).
+  static bool GetSocketName(const int fd, std::string* result);
+
+  bool DetachSocket(std::string* error_msg) const;
+
+  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
+};
+
 // static
-FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd) {
+FileDescriptorInfo* FileDescriptorInfo::CreateFromFd(int fd, std::string* error_msg) {
   struct stat f_stat;
   // This should never happen; the zygote should always have the right set
   // of permissions required to stat all its open files.
   if (TEMP_FAILURE_RETRY(fstat(fd, &f_stat)) == -1) {
-    PLOG(ERROR) << "Unable to stat fd " << fd;
-    return NULL;
+    *error_msg = android::base::StringPrintf("Unable to stat %d", fd);
+    return nullptr;
   }
 
   const FileDescriptorWhitelist* whitelist = FileDescriptorWhitelist::Get();
@@ -138,13 +181,15 @@
   if (S_ISSOCK(f_stat.st_mode)) {
     std::string socket_name;
     if (!GetSocketName(fd, &socket_name)) {
-      return NULL;
+      *error_msg = "Unable to get socket name";
+      return nullptr;
     }
 
     if (!whitelist->IsAllowed(socket_name)) {
-      LOG(ERROR) << "Socket name not whitelisted : " << socket_name
-                 << " (fd=" << fd << ")";
-      return NULL;
+      *error_msg = android::base::StringPrintf("Socket name not whitelisted : %s (fd=%d)",
+                                               socket_name.c_str(),
+                                               fd);
+      return nullptr;
     }
 
     return new FileDescriptorInfo(fd);
@@ -161,19 +206,22 @@
   // with the child process across forks but those should have been closed
   // before we got to this point.
   if (!S_ISCHR(f_stat.st_mode) && !S_ISREG(f_stat.st_mode)) {
-    LOG(ERROR) << "Unsupported st_mode " << f_stat.st_mode;
-    return NULL;
+    *error_msg = android::base::StringPrintf("Unsupported st_mode %u", f_stat.st_mode);
+    return nullptr;
   }
 
   std::string file_path;
   const std::string fd_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
   if (!android::base::Readlink(fd_path, &file_path)) {
-    return NULL;
+    *error_msg = android::base::StringPrintf("Could not read fd link %s: %s",
+                                             fd_path.c_str(),
+                                             strerror(errno));
+    return nullptr;
   }
 
   if (!whitelist->IsAllowed(file_path)) {
-    LOG(ERROR) << "Not whitelisted : " << file_path;
-    return NULL;
+    *error_msg = std::string("Not whitelisted : ").append(file_path);
+    return nullptr;
   }
 
   // File descriptor flags : currently on FD_CLOEXEC. We can set these
@@ -181,8 +229,11 @@
   // there won't be any races.
   const int fd_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD));
   if (fd_flags == -1) {
-    PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFD)";
-    return NULL;
+    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFD) (%s): %s",
+                                             fd,
+                                             file_path.c_str(),
+                                             strerror(errno));
+    return nullptr;
   }
 
   // File status flags :
@@ -199,8 +250,11 @@
   //   their presence and pass them in to open().
   int fs_flags = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFL));
   if (fs_flags == -1) {
-    PLOG(ERROR) << "Failed fcntl(" << fd << ", F_GETFL)";
-    return NULL;
+    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_GETFL) (%s): %s",
+                                             fd,
+                                             file_path.c_str(),
+                                             strerror(errno));
+    return nullptr;
   }
 
   // File offset : Ignore the offset for non seekable files.
@@ -225,9 +279,9 @@
   return f_stat.st_ino == stat.st_ino && f_stat.st_dev == stat.st_dev;
 }
 
-bool FileDescriptorInfo::ReopenOrDetach() const {
+bool FileDescriptorInfo::ReopenOrDetach(std::string* error_msg) const {
   if (is_sock) {
-    return DetachSocket();
+    return DetachSocket(error_msg);
   }
 
   // NOTE: This might happen if the file was unlinked after being opened.
@@ -236,31 +290,49 @@
   const int new_fd = TEMP_FAILURE_RETRY(open(file_path.c_str(), open_flags));
 
   if (new_fd == -1) {
-    PLOG(ERROR) << "Failed open(" << file_path << ", " << open_flags << ")";
+    *error_msg = android::base::StringPrintf("Failed open(%s, %i): %s",
+                                             file_path.c_str(),
+                                             open_flags,
+                                             strerror(errno));
     return false;
   }
 
   if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFD, fd_flags)) == -1) {
     close(new_fd);
-    PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFD, " << fd_flags << ")";
+    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFD, %d) (%s): %s",
+                                             new_fd,
+                                             fd_flags,
+                                             file_path.c_str(),
+                                             strerror(errno));
     return false;
   }
 
   if (TEMP_FAILURE_RETRY(fcntl(new_fd, F_SETFL, fs_flags)) == -1) {
     close(new_fd);
-    PLOG(ERROR) << "Failed fcntl(" << new_fd << ", F_SETFL, " << fs_flags << ")";
+    *error_msg = android::base::StringPrintf("Failed fcntl(%d, F_SETFL, %d) (%s): %s",
+                                             new_fd,
+                                             fs_flags,
+                                             file_path.c_str(),
+                                             strerror(errno));
     return false;
   }
 
   if (offset != -1 && TEMP_FAILURE_RETRY(lseek64(new_fd, offset, SEEK_SET)) == -1) {
     close(new_fd);
-    PLOG(ERROR) << "Failed lseek64(" << new_fd << ", SEEK_SET)";
+    *error_msg = android::base::StringPrintf("Failed lseek64(%d, SEEK_SET) (%s): %s",
+                                             new_fd,
+                                             file_path.c_str(),
+                                             strerror(errno));
     return false;
   }
 
   if (TEMP_FAILURE_RETRY(dup2(new_fd, fd)) == -1) {
     close(new_fd);
-    PLOG(ERROR) << "Failed dup2(" << fd << ", " << new_fd << ")";
+    *error_msg = android::base::StringPrintf("Failed dup2(%d, %d) (%s): %s",
+                                             fd,
+                                             new_fd,
+                                             file_path.c_str(),
+                                             strerror(errno));
     return false;
   }
 
@@ -336,20 +408,22 @@
   return true;
 }
 
-bool FileDescriptorInfo::DetachSocket() const {
+bool FileDescriptorInfo::DetachSocket(std::string* error_msg) const {
   const int dev_null_fd = open("/dev/null", O_RDWR);
   if (dev_null_fd < 0) {
-    PLOG(ERROR) << "Failed to open /dev/null";
+    *error_msg = std::string("Failed to open /dev/null: ").append(strerror(errno));
     return false;
   }
 
   if (dup2(dev_null_fd, fd) == -1) {
-    PLOG(ERROR) << "Failed dup2 on socket descriptor " << fd;
+    *error_msg = android::base::StringPrintf("Failed dup2 on socket descriptor %d: %s",
+                                             fd,
+                                             strerror(errno));
     return false;
   }
 
   if (close(dev_null_fd) == -1) {
-    PLOG(ERROR) << "Failed close(" << dev_null_fd << ")";
+    *error_msg = android::base::StringPrintf("Failed close(%d): %s", dev_null_fd, strerror(errno));
     return false;
   }
 
@@ -357,11 +431,12 @@
 }
 
 // static
-FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore) {
+FileDescriptorTable* FileDescriptorTable::Create(const std::vector<int>& fds_to_ignore,
+                                                 std::string* error_msg) {
   DIR* d = opendir(kFdPath);
-  if (d == NULL) {
-    PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath);
-    return NULL;
+  if (d == nullptr) {
+    *error_msg = std::string("Unable to open directory ").append(kFdPath);
+    return nullptr;
   }
   int dir_fd = dirfd(d);
   dirent* e;
@@ -377,7 +452,7 @@
       continue;
     }
 
-    FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
+    FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
     if (info == NULL) {
       if (closedir(d) == -1) {
         PLOG(ERROR) << "Unable to close directory";
@@ -388,19 +463,21 @@
   }
 
   if (closedir(d) == -1) {
-    PLOG(ERROR) << "Unable to close directory";
-    return NULL;
+    *error_msg = "Unable to close directory";
+    return nullptr;
   }
   return new FileDescriptorTable(open_fd_map);
 }
 
-bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore) {
+bool FileDescriptorTable::Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg) {
   std::set<int> open_fds;
 
   // First get the list of open descriptors.
   DIR* d = opendir(kFdPath);
   if (d == NULL) {
-    PLOG(ERROR) << "Unable to open directory " << std::string(kFdPath);
+    *error_msg = android::base::StringPrintf("Unable to open directory %s: %s",
+                                             kFdPath,
+                                             strerror(errno));
     return false;
   }
 
@@ -420,21 +497,21 @@
   }
 
   if (closedir(d) == -1) {
-    PLOG(ERROR) << "Unable to close directory";
+    *error_msg = android::base::StringPrintf("Unable to close directory: %s", strerror(errno));
     return false;
   }
 
-  return RestatInternal(open_fds);
+  return RestatInternal(open_fds, error_msg);
 }
 
 // Reopens all file descriptors that are contained in the table. Returns true
 // if all descriptors were successfully re-opened or detached, and false if an
 // error occurred.
-bool FileDescriptorTable::ReopenOrDetach() {
+bool FileDescriptorTable::ReopenOrDetach(std::string* error_msg) {
   std::unordered_map<int, FileDescriptorInfo*>::const_iterator it;
   for (it = open_fd_map_.begin(); it != open_fd_map_.end(); ++it) {
     const FileDescriptorInfo* info = it->second;
-    if (info == NULL || !info->ReopenOrDetach()) {
+    if (info == NULL || !info->ReopenOrDetach(error_msg)) {
       return false;
     }
   }
@@ -447,7 +524,7 @@
     : open_fd_map_(map) {
 }
 
-bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds) {
+bool FileDescriptorTable::RestatInternal(std::set<int>& open_fds, std::string* error_msg) {
   bool error = false;
 
   // Iterate through the list of file descriptors we've already recorded
@@ -455,6 +532,8 @@
   //
   // (a) they continue to be open.
   // (b) they refer to the same file.
+  //
+  // We'll only store the last error message.
   std::unordered_map<int, FileDescriptorInfo*>::iterator it = open_fd_map_.begin();
   while (it != open_fd_map_.end()) {
     std::set<int>::const_iterator element = open_fds.find(it->first);
@@ -475,7 +554,7 @@
         // The file descriptor refers to a different description. We must
         // update our entry in the table.
         delete it->second;
-        it->second = FileDescriptorInfo::CreateFromFd(*element);
+        it->second = FileDescriptorInfo::CreateFromFd(*element, error_msg);
         if (it->second == NULL) {
           // The descriptor no longer no longer refers to a whitelisted file.
           // We flag an error and remove it from the list of files we're
@@ -510,7 +589,7 @@
     std::set<int>::const_iterator it;
     for (it = open_fds.begin(); it != open_fds.end(); ++it) {
       const int fd = (*it);
-      FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd);
+      FileDescriptorInfo* info = FileDescriptorInfo::CreateFromFd(fd, error_msg);
       if (info == NULL) {
         // A newly opened file is not on the whitelist. Flag an error and
         // continue.
diff --git a/core/jni/fd_utils.h b/core/jni/fd_utils.h
index a39e387..a3570d7 100644
--- a/core/jni/fd_utils.h
+++ b/core/jni/fd_utils.h
@@ -28,6 +28,8 @@
 
 #include <android-base/macros.h>
 
+class FileDescriptorInfo;
+
 // Whitelist of open paths that the zygote is allowed to keep open.
 //
 // In addition to the paths listed in kPathWhitelist in file_utils.cpp, and
@@ -66,49 +68,6 @@
   DISALLOW_COPY_AND_ASSIGN(FileDescriptorWhitelist);
 };
 
-// Keeps track of all relevant information (flags, offset etc.) of an
-// open zygote file descriptor.
-class FileDescriptorInfo {
- public:
-  // Create a FileDescriptorInfo for a given file descriptor. Returns
-  // |NULL| if an error occurred.
-  static FileDescriptorInfo* CreateFromFd(int fd);
-
-  // Checks whether the file descriptor associated with this object
-  // refers to the same description.
-  bool Restat() const;
-
-  bool ReopenOrDetach() const;
-
-  const int fd;
-  const struct stat stat;
-  const std::string file_path;
-  const int open_flags;
-  const int fd_flags;
-  const int fs_flags;
-  const off_t offset;
-  const bool is_sock;
-
- private:
-  FileDescriptorInfo(int fd);
-
-  FileDescriptorInfo(struct stat stat, const std::string& file_path, int fd, int open_flags,
-                     int fd_flags, int fs_flags, off_t offset);
-
-  // Returns the locally-bound name of the socket |fd|. Returns true
-  // iff. all of the following hold :
-  //
-  // - the socket's sa_family is AF_UNIX.
-  // - the length of the path is greater than zero (i.e, not an unnamed socket).
-  // - the first byte of the path isn't zero (i.e, not a socket with an abstract
-  //   address).
-  static bool GetSocketName(const int fd, std::string* result);
-
-  bool DetachSocket() const;
-
-  DISALLOW_COPY_AND_ASSIGN(FileDescriptorInfo);
-};
-
 // A FileDescriptorTable is a collection of FileDescriptorInfo objects
 // keyed by their FDs.
 class FileDescriptorTable {
@@ -116,19 +75,20 @@
   // Creates a new FileDescriptorTable. This function scans
   // /proc/self/fd for the list of open file descriptors and collects
   // information about them. Returns NULL if an error occurs.
-  static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore);
+  static FileDescriptorTable* Create(const std::vector<int>& fds_to_ignore,
+                                     std::string* error_msg);
 
-  bool Restat(const std::vector<int>& fds_to_ignore);
+  bool Restat(const std::vector<int>& fds_to_ignore, std::string* error_msg);
 
   // Reopens all file descriptors that are contained in the table. Returns true
   // if all descriptors were successfully re-opened or detached, and false if an
   // error occurred.
-  bool ReopenOrDetach();
+  bool ReopenOrDetach(std::string* error_msg);
 
  private:
   FileDescriptorTable(const std::unordered_map<int, FileDescriptorInfo*>& map);
 
-  bool RestatInternal(std::set<int>& open_fds);
+  bool RestatInternal(std::set<int>& open_fds, std::string* error_msg);
 
   static int ParseFd(dirent* e, int dir_fd);
 
diff --git a/core/proto/android/server/powermanagerservice.proto b/core/proto/android/server/powermanagerservice.proto
index 64aa98b..c58de56 100644
--- a/core/proto/android/server/powermanagerservice.proto
+++ b/core/proto/android/server/powermanagerservice.proto
@@ -198,7 +198,7 @@
     }
 
     optional .android.os.WakeLockLevelEnum lock_level = 1;
-    optional string tag = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
+    optional string tag = 2;
     optional WakeLockFlagsProto flags = 3;
     optional bool is_disabled = 4;
     // Acquire time in ms
diff --git a/core/proto/android/service/graphicsstats.proto b/core/proto/android/service/graphicsstats.proto
index f422065..c2fedf5 100644
--- a/core/proto/android/service/graphicsstats.proto
+++ b/core/proto/android/service/graphicsstats.proto
@@ -56,7 +56,7 @@
     // Number of "missed vsync" events.
     optional int32 missed_vsync_count = 3;
 
-    // Number of "high input latency" events.
+    // Number of frames in triple-buffering scenario (high input latency)
     optional int32 high_input_latency_count = 4;
 
     // Number of "slow UI thread" events.
@@ -67,6 +67,9 @@
 
     // Number of "slow draw" events.
     optional int32 slow_draw_count = 7;
+
+    // Number of frames that missed their deadline (aka, visibly janked)
+    optional int32 missed_deadline_count = 8;
 }
 
 message GraphicsStatsHistogramBucketProto {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6c0be1b..0a56ef7 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -160,13 +160,13 @@
     <string name="RestrictedStateContent">Temporarily turned off by your carrier</string>
 
     <!-- Displayed to tell the user that they should switch their network preference. -->
-    <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach network</string>
+    <string name="NetworkPreferenceSwitchTitle">Can\u2019t reach mobile network</string>
     <!-- Displayed to tell the user that they should switch their network preference. -->
-    <string name="NetworkPreferenceSwitchSummary">To improve reception, try changing the type selected at Settings &gt; Network &amp; internet &gt; Mobile networks &gt; Preferred network type."</string>
+    <string name="NetworkPreferenceSwitchSummary">Try changing preferred network. Tap to change.</string>
     <!-- Displayed to tell the user that emergency calls might not be available. -->
-    <string name="EmergencyCallWarningTitle">Wi\u2011Fi calling is active</string>
+    <string name="EmergencyCallWarningTitle">Emergency calling unavailable</string>
     <!-- Displayed to tell the user that emergency calls might not be available. -->
-    <string name="EmergencyCallWarningSummary">Emergency calls require a mobile network.</string>
+    <string name="EmergencyCallWarningSummary">Can\u2019t make emergency calls over Wi\u2011Fi</string>
 
     <!-- Telephony notification channel name for a channel containing network alert notifications. -->
     <string name="notification_channel_network_alert">Alerts</string>
diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
index c3af6bd..4642694 100644
--- a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
+++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk
@@ -24,5 +24,6 @@
 LOCAL_SDK_VERSION := current
 LOCAL_CERTIFICATE := platform
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
 include $(BUILD_PACKAGE)
 
diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
index 34016ed..f852c7a 100644
--- a/core/tests/coretests/BinderProxyCountingTestService/Android.mk
+++ b/core/tests/coretests/BinderProxyCountingTestService/Android.mk
@@ -24,5 +24,6 @@
 LOCAL_PRIVATE_PLATFORM_APIS := true
 LOCAL_CERTIFICATE := platform
 
+LOCAL_COMPATIBILITY_SUITE := device-tests
 include $(BUILD_PACKAGE)
 
diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk
index e04536b..a5872a5 100644
--- a/core/tests/coretests/BstatsTestApp/Android.mk
+++ b/core/tests/coretests/BstatsTestApp/Android.mk
@@ -30,4 +30,5 @@
 LOCAL_DEX_PREOPT := false
 LOCAL_PROGUARD_ENABLED := disabled
 
-include $(BUILD_PACKAGE)
\ No newline at end of file
+LOCAL_COMPATIBILITY_SUITE := device-tests
+include $(BUILD_PACKAGE)
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 22a261e..73fb713 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -383,6 +383,7 @@
                     Settings.Global.SYS_STORAGE_THRESHOLD_PERCENTAGE,
                     Settings.Global.SYS_VDSO,
                     Settings.Global.SYS_UIDCPUPOWER,
+                    Settings.Global.SYS_TRACED,
                     Settings.Global.FPS_DEVISOR,
                     Settings.Global.TCP_DEFAULT_INIT_RWND,
                     Settings.Global.TETHER_DUN_APN,
diff --git a/core/tests/featureflagtests/AndroidTest.xml b/core/tests/featureflagtests/AndroidTest.xml
index 44f9c3e..38c048a 100644
--- a/core/tests/featureflagtests/AndroidTest.xml
+++ b/core/tests/featureflagtests/AndroidTest.xml
@@ -15,14 +15,16 @@
   limitations under the License.
   -->
 <configuration description="Runs Frameworks Utility Tests.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="FrameworksCoreFeatureFlagTests.apk" />
     </target_preparer>
 
-    <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="FrameworksCoreFeatureFlagTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.coretests.featureflagtests" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
     </test>
 </configuration>
diff --git a/core/tests/overlaytests/device/AndroidTest.xml b/core/tests/overlaytests/device/AndroidTest.xml
index f069835..6507839 100644
--- a/core/tests/overlaytests/device/AndroidTest.xml
+++ b/core/tests/overlaytests/device/AndroidTest.xml
@@ -17,8 +17,10 @@
 <configuration description="Test module config for OverlayDeviceTests">
     <option name="test-tag" value="OverlayDeviceTests" />
     <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
 
     <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+        <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="OverlayDeviceTests.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_AppOverlayOne.apk" />
         <option name="test-file-name" value="OverlayDeviceTests_AppOverlayTwo.apk" />
@@ -42,6 +44,5 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package" value="com.android.overlaytest" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
     </test>
 </configuration>
diff --git a/core/tests/privacytests/AndroidTest.xml b/core/tests/privacytests/AndroidTest.xml
index a43f48e..8098c14 100644
--- a/core/tests/privacytests/AndroidTest.xml
+++ b/core/tests/privacytests/AndroidTest.xml
@@ -14,12 +14,14 @@
      limitations under the License.
 -->
 <configuration description="Runs Privacy Tests.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="FrameworksPrivacyLibraryTests.apk" />
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.coretests.privacy" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
     </test>
-</configuration>
\ No newline at end of file
+</configuration>
diff --git a/core/tests/utiltests/AndroidTest.xml b/core/tests/utiltests/AndroidTest.xml
index 65bb8de..270d773 100644
--- a/core/tests/utiltests/AndroidTest.xml
+++ b/core/tests/utiltests/AndroidTest.xml
@@ -14,14 +14,16 @@
      limitations under the License.
 -->
 <configuration description="Runs Frameworks Utility Tests.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="FrameworksUtilTests.apk" />
     </target_preparer>
 
-    <option name="test-suite-tag" value="apct" />
     <option name="test-tag" value="FrameworksUtilTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.frameworks.utiltests" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
     </test>
 </configuration>
diff --git a/core/tests/webkit/AndroidTest.xml b/core/tests/webkit/AndroidTest.xml
index 78cfa46..4c50b7d 100644
--- a/core/tests/webkit/AndroidTest.xml
+++ b/core/tests/webkit/AndroidTest.xml
@@ -14,7 +14,9 @@
      limitations under the License.
 -->
 <configuration description="Runs Frameworks WebView Loading Tests.">
-    <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="test-file-name" value="WebViewLoadingTests.apk" />
         <option name="test-file-name" value="WebViewLoadingOnDiskTestApk.apk" />
         <option name="test-file-name" value="WebViewLoadingFromApkTestApk.apk" />
@@ -24,6 +26,5 @@
 
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.webkit.tests" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
     </test>
 </configuration>
diff --git a/core/tests/webkit/apk_with_native_libs/Android.mk b/core/tests/webkit/apk_with_native_libs/Android.mk
index c51de6a..e18a7e0 100644
--- a/core/tests/webkit/apk_with_native_libs/Android.mk
+++ b/core/tests/webkit/apk_with_native_libs/Android.mk
@@ -45,6 +45,7 @@
 LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
 LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
 LOCAL_MULTILIB := $(MY_MULTILIB)
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 include $(BUILD_PACKAGE)
 
@@ -65,5 +66,6 @@
 LOCAL_SDK_VERSION := $(MY_SDK_VERSION)
 LOCAL_PROGUARD_ENABLED := $(MY_PROGUARD_ENABLED)
 LOCAL_MULTILIB := $(MY_MULTILIB)
+LOCAL_COMPATIBILITY_SUITE := device-tests
 
 include $(BUILD_PACKAGE)
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index 07df045..5dc4463 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -454,8 +454,7 @@
 
         throwIfHasHwBitmapInSwMode(paint);
         nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
-                x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */,
-                0 /* measured text offset */);
+                x, y, isRtl, paint.getNativeInstance(), 0 /* measured text */);
     }
 
     public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
@@ -486,19 +485,16 @@
             char[] buf = TemporaryBuffer.obtain(contextLen);
             TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
             long measuredTextPtr = 0;
-            int measuredTextOffset = 0;
             if (text instanceof PrecomputedText) {
                 PrecomputedText mt = (PrecomputedText) text;
                 int paraIndex = mt.findParaIndex(start);
                 if (end <= mt.getParagraphEnd(paraIndex)) {
-                    // Only suppor the same paragraph.
+                    // Only suppor the text in the same paragraph.
                     measuredTextPtr = mt.getMeasuredParagraph(paraIndex).getNativePtr();
-                    measuredTextOffset = start - mt.getParagraphStart(paraIndex);
                 }
             }
             nDrawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
-                    0, contextLen, x, y, isRtl, paint.getNativeInstance(),
-                    measuredTextPtr, measuredTextOffset);
+                    0, contextLen, x, y, isRtl, paint.getNativeInstance(), measuredTextPtr);
             TemporaryBuffer.recycle(buf);
         }
     }
@@ -647,7 +643,7 @@
 
     private static native void nDrawTextRun(long nativeCanvas, char[] text, int start, int count,
             int contextStart, int contextCount, float x, float y, boolean isRtl, long nativePaint,
-            long nativePrecomputedText, int measuredTextOffset);
+            long nativePrecomputedText);
 
     private static native void nDrawTextOnPath(long nativeCanvas, char[] text, int index, int count,
             long nativePath, float hOffset, float vOffset, int bidiFlags, long nativePaint);
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index cf29e43..8110664 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -129,22 +129,42 @@
             totalDuration -= forgiveAmount;
         }
     }
+
     LOG_ALWAYS_FATAL_IF(totalDuration <= 0, "Impossible totalDuration %" PRId64, totalDuration);
     mData->reportFrame(totalDuration);
     (*mGlobalData)->reportFrame(totalDuration);
 
-    // Keep the fast path as fast as possible.
-    if (CC_LIKELY(totalDuration < mFrameInterval)) {
-        return;
-    }
-
     // Only things like Surface.lockHardwareCanvas() are exempt from tracking
-    if (frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS) {
+    if (CC_UNLIKELY(frame[FrameInfoIndex::Flags] & EXEMPT_FRAMES_FLAGS)) {
         return;
     }
 
-    mData->reportJank();
-    (*mGlobalData)->reportJank();
+    if (totalDuration > mFrameInterval) {
+        mData->reportJank();
+        (*mGlobalData)->reportJank();
+    }
+
+    bool isTripleBuffered = mSwapDeadline > frame[FrameInfoIndex::IntendedVsync];
+
+    mSwapDeadline = std::max(mSwapDeadline + mFrameInterval,
+                             frame[FrameInfoIndex::IntendedVsync] + mFrameInterval);
+
+    // If we hit the deadline, cool!
+    if (frame[FrameInfoIndex::FrameCompleted] < mSwapDeadline) {
+        if (isTripleBuffered) {
+            mData->reportJankType(JankType::kHighInputLatency);
+            (*mGlobalData)->reportJankType(JankType::kHighInputLatency);
+        }
+        return;
+    }
+
+    mData->reportJankType(JankType::kMissedDeadline);
+    (*mGlobalData)->reportJankType(JankType::kMissedDeadline);
+
+    // Janked, reset the swap deadline
+    nsecs_t jitterNanos = frame[FrameInfoIndex::FrameCompleted] - frame[FrameInfoIndex::Vsync];
+    nsecs_t lastFrameOffset = jitterNanos % mFrameInterval;
+    mSwapDeadline = frame[FrameInfoIndex::FrameCompleted] - lastFrameOffset + mFrameInterval;
 
     for (int i = 0; i < NUM_BUCKETS; i++) {
         int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end);
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index dc6a7ff..110211e 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -75,6 +75,7 @@
 
     std::array<int64_t, NUM_BUCKETS> mThresholds;
     int64_t mFrameInterval;
+    nsecs_t mSwapDeadline;
     // The amount of time we will erase from the total duration to account
     // for SF vsync offsets with HWC2 blocking dequeueBuffers.
     // (Vsync + mDequeueBlockTolerance) is the point at which we expect
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index b392ecd..f9cf549 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -23,8 +23,7 @@
 
 static const char* JANK_TYPE_NAMES[] = {
         "Missed Vsync",        "High input latency",       "Slow UI thread",
-        "Slow bitmap uploads", "Slow issue draw commands",
-};
+        "Slow bitmap uploads", "Slow issue draw commands", "Frame deadline missed"};
 
 // The bucketing algorithm controls so to speak
 // If a frame is <= to this it goes in bucket 0
diff --git a/libs/hwui/ProfileData.h b/libs/hwui/ProfileData.h
index 1e688ab..564920b 100644
--- a/libs/hwui/ProfileData.h
+++ b/libs/hwui/ProfileData.h
@@ -33,6 +33,7 @@
     kSlowUI,
     kSlowSync,
     kSlowRT,
+    kMissedDeadline,
 
     // must be last
     NUM_BUCKETS,
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 2b0b22d..40b811d 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -764,6 +764,13 @@
 void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
                                   const SkPaint& paint, const SkPath& path, size_t start,
                                   size_t end) {
+    // Set align to left for drawing, as we don't want individual
+    // glyphs centered or right-aligned; the offsets take care of
+    // that portion of the alignment.
+    SkPaint paintCopy(paint);
+    paintCopy.setTextAlign(SkPaint::kLeft_Align);
+    SkASSERT(paintCopy.getTextEncoding() == SkPaint::kGlyphID_TextEncoding);
+
     const int N = end - start;
     SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
     SkRSXform* xform = (SkRSXform*)storage.get();
@@ -788,7 +795,7 @@
         xform[i - start].fTy = pos.y() + tan.x() * y - halfWidth * tan.y();
     }
 
-    this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
+    this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paintCopy);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index ad4c8be..20543df 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -158,13 +158,13 @@
 
 void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, float x,
                       float y, minikin::Bidi bidiFlags, const Paint& origPaint,
-                      const Typeface* typeface, minikin::MeasuredText* mt, int mtOffset) {
+                      const Typeface* typeface, minikin::MeasuredText* mt) {
     // minikin may modify the original paint
     Paint paint(origPaint);
 
     minikin::Layout layout =
             MinikinUtils::doLayout(&paint, bidiFlags, typeface, text, start, count, contextCount,
-                                   mt, mtOffset);
+                                   mt);
 
     x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
 
@@ -212,8 +212,7 @@
                             const Typeface* typeface) {
     Paint paintCopy(paint);
     minikin::Layout layout =
-            MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count, nullptr,
-                                   0);
+            MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count, nullptr);
     hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
 
     // Set align to left for drawing, as we don't want individual
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index fabb8d2..d04bb2e 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -270,7 +270,7 @@
      */
     void drawText(const uint16_t* text, int start, int count, int contextCount, float x, float y,
                   minikin::Bidi bidiFlags, const Paint& origPaint, const Typeface* typeface,
-                  minikin::MeasuredText* mt, int mtOffset);
+                  minikin::MeasuredText* mt);
 
     void drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiFlags,
                         const SkPath& path, float hOffset, float vOffset, const Paint& paint,
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index a0d000d..5b69bb7 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -49,8 +49,7 @@
 
 minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
                                        const Typeface* typeface, const uint16_t* buf, size_t start,
-                                       size_t count, size_t bufSize, minikin::MeasuredText* mt,
-                                       int mtOffset) {
+                                       size_t count, size_t bufSize, minikin::MeasuredText* mt) {
     minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
     minikin::Layout layout;
 
@@ -62,15 +61,9 @@
 
     if (mt == nullptr) {
         layout.doLayout(textBuf,range, bidiFlags, minikinPaint, startHyphen, endHyphen);
-        return layout;
+    } else {
+        mt->buildLayout(textBuf, range, minikinPaint, bidiFlags, startHyphen, endHyphen, &layout);
     }
-
-    if (mt->buildLayout(textBuf, range, minikinPaint, bidiFlags, mtOffset, startHyphen, endHyphen,
-                        &layout)) {
-        return layout;
-    }
-
-    layout.doLayout(textBuf, range, bidiFlags, minikinPaint, startHyphen, endHyphen);
     return layout;
 }
 
@@ -85,7 +78,8 @@
     const minikin::EndHyphenEdit endHyphen = minikin::endHyphenEdit(hyphenEdit);
 
     return minikin::Layout::measureText(textBuf, range, bidiFlags, minikinPaint, startHyphen,
-                                        endHyphen, advances, nullptr /* extent */);
+                                        endHyphen, advances, nullptr /* extent */,
+                                        nullptr /* layout pieces */);
 }
 
 bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 124fe4f..77dfbb2 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -45,7 +45,7 @@
     ANDROID_API static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags,
                                                 const Typeface* typeface, const uint16_t* buf,
                                                 size_t start, size_t count, size_t bufSize,
-                                                minikin::MeasuredText* mt, int mtOffset);
+                                                minikin::MeasuredText* mt);
 
     ANDROID_API static float measureText(const Paint* paint, minikin::Bidi bidiFlags,
                                          const Typeface* typeface, const uint16_t* buf,
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 25c76eb..62d78e7 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -148,31 +148,6 @@
 // Recording Canvas draw operations: Bitmaps
 // ----------------------------------------------------------------------------
 
-inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
-                                         sk_sp<SkColorFilter> colorSpaceFilter) {
-    if ((origPaint && origPaint->isAntiAlias()) || colorSpaceFilter) {
-        if (origPaint) {
-            *tmpPaint = *origPaint;
-        }
-
-        if (colorSpaceFilter) {
-            if (tmpPaint->getColorFilter()) {
-                tmpPaint->setColorFilter(
-                        SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorSpaceFilter));
-            } else {
-                tmpPaint->setColorFilter(colorSpaceFilter);
-            }
-            LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
-        }
-
-
-        // disabling AA on bitmap draws matches legacy HWUI behavior
-        tmpPaint->setAntiAlias(false);
-        return tmpPaint;
-    } else {
-        return origPaint;
-    }
-}
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
     SkPaint tmpPaint;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 0e5dbdb..93807a5 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -88,6 +88,45 @@
      *  @param height used to calculate recording bounds.
      */
     void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);
+
+    inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
+                                             sk_sp<SkColorFilter> colorSpaceFilter) {
+        bool fixBlending = false;
+        bool fixAA = false;
+        if (origPaint) {
+            // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
+            // older.
+            fixBlending = sApiLevel <= 27 && origPaint->getBlendMode() == SkBlendMode::kClear;
+            fixAA = origPaint->isAntiAlias();
+        }
+
+        if (fixBlending || fixAA || colorSpaceFilter) {
+            if (origPaint) {
+                *tmpPaint = *origPaint;
+            }
+
+            if (fixBlending) {
+                tmpPaint->setBlendMode(SkBlendMode::kDstOut);
+            }
+
+            if (colorSpaceFilter) {
+                if (tmpPaint->getColorFilter()) {
+                    tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter(
+                            tmpPaint->refColorFilter(), colorSpaceFilter));
+                } else {
+                    tmpPaint->setColorFilter(colorSpaceFilter);
+                }
+                LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
+            }
+
+            // disabling AA on bitmap draws matches legacy HWUI behavior
+            tmpPaint->setAntiAlias(false);
+            return tmpPaint;
+        } else {
+            return origPaint;
+        }
+    }
+
 };
 
 };  // namespace skiapipeline
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index e0303a8..599226b 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -176,6 +176,8 @@
     summary->set_slow_bitmap_upload_count(summary->slow_bitmap_upload_count() +
                                           data->jankTypeCount(kSlowSync));
     summary->set_slow_draw_count(summary->slow_draw_count() + data->jankTypeCount(kSlowRT));
+    summary->set_missed_deadline_count(summary->missed_deadline_count()
+            + data->jankTypeCount(kMissedDeadline));
 
     bool creatingHistogram = false;
     if (proto->histogram_size() == 0) {
@@ -246,6 +248,7 @@
     dprintf(fd, "\nNumber Slow UI thread: %d", summary.slow_ui_thread_count());
     dprintf(fd, "\nNumber Slow bitmap uploads: %d", summary.slow_bitmap_upload_count());
     dprintf(fd, "\nNumber Slow issue draw commands: %d", summary.slow_draw_count());
+    dprintf(fd, "\nNumber Frame deadline missed: %d", summary.missed_deadline_count());
     dprintf(fd, "\nHISTOGRAM:");
     for (const auto& it : proto->histogram()) {
         dprintf(fd, " %dms=%d", it.render_millis(), it.frame_count());
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 51cf772..b99854e 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -125,7 +125,7 @@
     SkPaint glyphPaint(paint);
     glyphPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR,
-            glyphPaint, nullptr, nullptr /* measured text */, 0 /* measured text offset */);
+            glyphPaint, nullptr, nullptr /* measured text */);
 }
 
 void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
diff --git a/libs/hwui/tests/common/scenes/JankyScene.cpp b/libs/hwui/tests/common/scenes/JankyScene.cpp
new file mode 100644
index 0000000..f5e6b31
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/JankyScene.cpp
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+
+#include <unistd.h>
+
+class JankyScene;
+
+static TestScene::Registrar _JankyScene(TestScene::Info{
+        "janky",
+        "A scene that intentionally janks just enough to stay in "
+        "triple buffering.",
+        TestScene::simpleCreateScene<JankyScene>});
+
+class JankyScene : public TestScene {
+public:
+    sp<RenderNode> card;
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
+            canvas.drawColor(0xFF0000FF, SkBlendMode::kSrcOver);
+        });
+        canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);  // background
+        canvas.drawRenderNode(card.get());
+    }
+
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 150;
+        if (curFrame & 1) {
+            usleep(15000);
+        }
+        // we animate left and top coordinates, which in turn animates width and
+        // height (bottom/right coordinates are fixed)
+        card->mutateStagingProperties().setLeftTop(curFrame, curFrame);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+};
\ No newline at end of file
diff --git a/media/OWNERS b/media/OWNERS
index f198f43..3e9a25e 100644
--- a/media/OWNERS
+++ b/media/OWNERS
@@ -4,3 +4,4 @@
 marcone@google.com
 sungsoo@google.com
 wjia@google.com
+jaewan@google.com
diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java
index b51c662..40be018 100644
--- a/media/java/android/media/MediaController2.java
+++ b/media/java/android/media/MediaController2.java
@@ -836,20 +836,30 @@
     }
 
     /**
-     * Sets the index of current DataSourceDesc in the play list to be played.
+     * Skips to the item in the playlist.
+     * <p>
+     * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)}.
      *
-     * @param item the index of DataSourceDesc in the play list you want to play
-     * @throws IllegalArgumentException if the play list is null
-     * @throws NullPointerException if index is outside play list range
+     * @param item The item in the playlist you want to play
      */
     public void skipToPlaylistItem(@NonNull MediaItem2 item) {
         mProvider.skipToPlaylistItem_impl(item);
     }
 
+    /**
+     * Skips to the previous item in the playlist.
+     * <p>
+     * This calls {@link MediaPlaylistAgent#skipToPreviousItem()}.
+     */
     public void skipToPreviousItem() {
         mProvider.skipToPreviousItem_impl();
     }
 
+    /**
+     * Skips to the next item in the playlist.
+     * <p>
+     * This calls {@link MediaPlaylistAgent#skipToNextItem()}.
+     */
     public void skipToNextItem() {
         mProvider.skipToNextItem_impl();
     }
diff --git a/media/java/android/media/MediaPlayer2Impl.java b/media/java/android/media/MediaPlayer2Impl.java
index 1c4d898..030e50d 100644
--- a/media/java/android/media/MediaPlayer2Impl.java
+++ b/media/java/android/media/MediaPlayer2Impl.java
@@ -82,7 +82,6 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.atomic.AtomicInteger;
 
-
 /**
  * @hide
  */
@@ -118,6 +117,7 @@
 
     private AtomicInteger mBufferedPercentageCurrent;
     private AtomicInteger mBufferedPercentageNext;
+    private volatile float mVolume = 1.0f;
 
     // Modular DRM
     private final Object mDrmLock = new Object();
@@ -553,6 +553,7 @@
         addTask(new Task(CALL_COMPLETED_SET_PLAYER_VOLUME, false) {
             @Override
             void process() {
+                mVolume = volume;
                 _setVolume(volume, volume);
             }
         });
@@ -567,8 +568,7 @@
      */
     @Override
     public float getPlayerVolume() {
-        // TODO: get real volume
-        return 1.0f;
+        return mVolume;
     }
 
     /**
@@ -3227,9 +3227,7 @@
     @Override
     public void clearMediaPlayer2EventCallback() {
         synchronized (mEventCbLock) {
-            for (Pair<Executor, MediaPlayer2EventCallback> cb : mEventCallbackRecords) {
-                mEventCallbackRecords.remove(cb);
-            }
+            mEventCallbackRecords.clear();
         }
     }
 
@@ -3300,9 +3298,7 @@
     @Override
     public void clearDrmEventCallback() {
         synchronized (mDrmEventCbLock) {
-            for (Pair<Executor, DrmEventCallback> cb : mDrmEventCallbackRecords) {
-                mDrmEventCallbackRecords.remove(cb);
-            }
+            mDrmEventCallbackRecords.clear();
         }
     }
 
diff --git a/media/java/android/media/MediaPlaylistAgent.java b/media/java/android/media/MediaPlaylistAgent.java
index 1d7520f..6588474 100644
--- a/media/java/android/media/MediaPlaylistAgent.java
+++ b/media/java/android/media/MediaPlaylistAgent.java
@@ -266,10 +266,16 @@
         mProvider.skipToPlaylistItem_impl(item);
     }
 
+    /**
+     * Skips to the previous item in the playlist.
+     */
     public void skipToPreviousItem() {
         mProvider.skipToPreviousItem_impl();
     }
 
+    /**
+     * Skips to the next item in the playlist.
+     */
     public void skipToNextItem() {
         mProvider.skipToNextItem_impl();
     }
diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java
index 91bface..a7aa3a7 100644
--- a/media/java/android/media/MediaSession2.java
+++ b/media/java/android/media/MediaSession2.java
@@ -1779,20 +1779,41 @@
     }
 
     /**
-     * Skip to the item in the play list.
+     * Skips to the item in the playlist.
+     * <p>
+     * This calls {@link MediaPlaylistAgent#skipToPlaylistItem(MediaItem2)} and the behavior depends
+     * on the playlist agent implementation, especially with the shuffle/repeat mode.
      *
-     * @param item item in the play list you want to play
-     * @throws IllegalArgumentException if the play list is null
-     * @throws NullPointerException if index is outside play list range
+     * @param item The item in the playlist you want to play
+     * @see #getShuffleMode()
+     * @see #getRepeatMode()
      */
     public void skipToPlaylistItem(@NonNull MediaItem2 item) {
         mProvider.skipToPlaylistItem_impl(item);
     }
 
+    /**
+     * Skips to the previous item.
+     * <p>
+     * This calls {@link MediaPlaylistAgent#skipToPreviousItem()} and the behavior depends on the
+     * playlist agent implementation, especially with the shuffle/repeat mode.
+     *
+     * @see #getShuffleMode()
+     * @see #getRepeatMode()
+     **/
     public void skipToPreviousItem() {
         mProvider.skipToPreviousItem_impl();
     }
 
+    /**
+     * Skips to the next item.
+     * <p>
+     * This calls {@link MediaPlaylistAgent#skipToNextItem()} and the behavior depends on the
+     * playlist agent implementation, especially with the shuffle/repeat mode.
+     *
+     * @see #getShuffleMode()
+     * @see #getRepeatMode()
+     */
     public void skipToNextItem() {
         mProvider.skipToNextItem_impl();
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index 2b6d09f..7081678 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -19,6 +19,7 @@
 import android.os.IDeviceIdleController;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.UserHandle;
 import android.support.annotation.VisibleForTesting;
 import android.util.ArraySet;
 import android.util.Log;
@@ -37,6 +38,7 @@
     private final IDeviceIdleController mDeviceIdleService;
     private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
     private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
+    private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>();
 
     public PowerWhitelistBackend() {
         mDeviceIdleService = IDeviceIdleController.Stub.asInterface(
@@ -62,6 +64,10 @@
         return mWhitelistedApps.contains(pkg);
     }
 
+    public boolean isSysWhitelistedExceptIdle(String pkg) {
+        return mSysWhitelistedAppsExceptIdle.contains(pkg);
+    }
+
     public void addApp(String pkg) {
         try {
             mDeviceIdleService.addPowerSaveWhitelistApp(pkg);
@@ -83,6 +89,7 @@
     @VisibleForTesting
     public void refreshList() {
         mSysWhitelistedApps.clear();
+        mSysWhitelistedAppsExceptIdle.clear();
         mWhitelistedApps.clear();
         try {
             String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
@@ -93,6 +100,11 @@
             for (String app : sysWhitelistedApps) {
                 mSysWhitelistedApps.add(app);
             }
+            String[] sysWhitelistedAppsExceptIdle =
+                    mDeviceIdleService.getSystemPowerWhitelistExceptIdle();
+            for (String app : sysWhitelistedAppsExceptIdle) {
+                mSysWhitelistedAppsExceptIdle.add(app);
+            }
         } catch (RemoteException e) {
             Log.w(TAG, "Unable to reach IDeviceIdleController", e);
         }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index c6a1428f..5a123af 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -48,6 +48,7 @@
         MockitoAnnotations.initMocks(this);
         doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
+        doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
         doNothing().when(mDeviceIdleService).addPowerSaveWhitelistApp(anyString());
         doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString());
         mPowerWhitelistBackend = new PowerWhitelistBackend(mDeviceIdleService);
@@ -88,6 +89,15 @@
         assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isSysWhitelisted(PACKAGE_TWO)).isFalse();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
+    }
 
+    @Test
+    public void testIsSystemWhitelistedExceptIdle() throws Exception {
+        doReturn(new String[]{PACKAGE_TWO}).when(
+                mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
+        mPowerWhitelistBackend.refreshList();
+
+        assertThat(mPowerWhitelistBackend.isSysWhitelistedExceptIdle(PACKAGE_ONE)).isFalse();
+        assertThat(mPowerWhitelistBackend.isSysWhitelistedExceptIdle(PACKAGE_TWO)).isTrue();
     }
 }
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index cfcfb95..4530f80 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -40,6 +40,7 @@
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
+import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -2594,15 +2595,26 @@
             loadSetting(stmt, Settings.Global.CALL_AUTO_RETRY, 0);
 
             // Set the preferred network mode to target desired value or Default
-            // value defined in RILConstants
-            int type;
-            type = RILConstants.PREFERRED_NETWORK_MODE;
-            loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, type);
+            // value defined in system property
+            String val = "";
+            String mode;
+            for (int phoneId = 0;
+                    phoneId < TelephonyManager.getDefault().getPhoneCount(); phoneId++) {
+                mode = TelephonyManager.getTelephonyProperty(phoneId,
+                        "ro.telephony.default_network",
+                        Integer.toString(RILConstants.PREFERRED_NETWORK_MODE));
+                if (phoneId == 0) {
+                    val = mode;
+                } else {
+                    val = val + "," + mode;
+                }
+            }
+            loadSetting(stmt, Settings.Global.PREFERRED_NETWORK_MODE, val);
 
             // Set the preferred cdma subscription source to target desired value or default
             // value defined in Phone
-            type = SystemProperties.getInt("ro.telephony.default_cdma_sub",
-                        Phone.PREFERRED_CDMA_SUBSCRIPTION);
+            int type = SystemProperties.getInt("ro.telephony.default_cdma_sub",
+                    Phone.PREFERRED_CDMA_SUBSCRIPTION);
             loadSetting(stmt, Settings.Global.CDMA_SUBSCRIPTION_MODE, type);
 
             loadIntegerSetting(stmt, Settings.Global.LOW_BATTERY_SOUND_TIMEOUT,
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
index 6131acc..aa2fb32 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/phone/NavGesture.java
@@ -16,6 +16,7 @@
 
 import android.graphics.Canvas;
 import android.view.MotionEvent;
+import android.view.View;
 
 import com.android.systemui.plugins.Plugin;
 import com.android.systemui.plugins.annotations.ProvidesInterface;
@@ -42,6 +43,8 @@
 
         public void onLayout(boolean changed, int left, int top, int right, int bottom);
 
+        public void onNavigationButtonLongPress(View v);
+
         public default void destroy() { }
     }
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 814b3ef..2c73f1e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1062,6 +1062,9 @@
     <!-- The text to clear all notifications. [CHAR LIMIT=60] -->
     <string name="clear_all_notifications_text">Clear all</string>
 
+    <!-- The text to show in the notifications shade when dnd is suppressing notifications. [CHAR LIMIT=100] -->
+    <string name="dnd_suppressing_shade_text">Do Not disturb is hiding notifications</string>
+
     <!-- Media projection permission dialog action text. [CHAR LIMIT=60] -->
     <string name="media_projection_action_text">Start now</string>
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index ef36610..8612445 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -80,4 +80,17 @@
      * Sent when overview is to be hidden.
      */
     void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
+
+    /**
+     * Sent when a user swipes up over the navigation bar to launch overview. Swipe up is determined
+     * by passing the touch slop in the direction towards launcher from navigation bar. During and
+     * after this event is sent the caller will continue to send motion events. The motion
+     * {@param event} passed after the touch slop was exceeded will also be passed after by
+     * {@link onMotionEvent}. Since motion events will be sent, motion up or cancel can still be
+     * sent to cancel overview regardless the current state of launcher (eg. if overview is already
+     * visible, this event will still be sent if user swipes up). When this signal is sent,
+     * navigation bar will not handle any gestures such as quick scrub or switch and the home button
+     * will cancel (long) press.
+     */
+    void onQuickStep(in MotionEvent event);
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index 846aadd..4799f39 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -36,11 +36,6 @@
     void startScreenPinning(int taskId) = 1;
 
     /**
-     * Called when the overview service has started the recents animation.
-     */
-    void onRecentsAnimationStarted() = 2;
-
-    /**
      * Specifies the text to be shown for onboarding the new swipe-up gesture to access recents.
      */
     void setRecentsOnboardingText(CharSequence text) = 3;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index f0952f9..08b4fee 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -182,6 +182,7 @@
             }
             button.setCompoundDrawables(iconDrawable, null, null, null);
             button.setOnClickListener(this);
+            button.setClickable(pendingIntent != null);
         }
 
         // Removing old views
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 041af0e..a4af6b2 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -102,15 +102,6 @@
             }
         }
 
-        public void onRecentsAnimationStarted() {
-            long token = Binder.clearCallingIdentity();
-            try {
-                mHandler.post(OverviewProxyService.this::notifyRecentsAnimationStarted);
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-        }
-
         public void onSplitScreenInvoked() {
             long token = Binder.clearCallingIdentity();
             try {
@@ -283,9 +274,9 @@
         }
     }
 
-    private void notifyRecentsAnimationStarted() {
+    public void notifyQuickStepStarted() {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
-            mConnectionCallbacks.get(i).onRecentsAnimationStarted();
+            mConnectionCallbacks.get(i).onQuickStepStarted();
         }
     }
 
@@ -300,7 +291,7 @@
 
     public interface OverviewProxyListener {
         default void onConnectionChanged(boolean isConnected) {}
-        default void onRecentsAnimationStarted() {}
+        default void onQuickStepStarted() {}
         default void onInteractionFlagsChanged(@InteractionType int flags) {}
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 4d54bdd..9a20c81 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -239,10 +239,13 @@
                         | WindowManager.LayoutParams.FLAG_SLIPPERY
                         | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN,
                 PixelFormat.TRANSLUCENT);
-        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+        lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS
+                | WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+
         if (!DEBUG_SCREENSHOT_ROUNDED_CORNERS) {
             lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
         }
+
         lp.setTitle("ScreenDecorOverlay");
         lp.gravity = Gravity.TOP | Gravity.LEFT;
         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -385,6 +388,7 @@
                 mBounds.set(mInfo.displayCutout.getBounds());
                 localBounds(mBoundingRect);
                 mInfo.displayCutout.getBounds().getBoundaryPath(mBoundingPath);
+                invalidate();
                 newVisible = VISIBLE;
             } else {
                 newVisible = GONE;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 0486a9d..a4927b7 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -63,7 +63,6 @@
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
-import android.view.View.OnTouchListener;
 import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.WindowManager.LayoutParams;
@@ -551,7 +550,6 @@
             alpha = (int) (interpolatedAlpha * 255);
         } else {
             if (mMenuState == MENU_STATE_CLOSE) {
-                mSettingsButton.setAlpha(menuAlpha);
                 mDismissButton.setAlpha(menuAlpha);
             }
             alpha = (int) (fraction * DISMISS_BACKGROUND_ALPHA * 255);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index d9359a4..c348187 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -189,7 +189,7 @@
         }
     }
 
-    public void onRecentsAnimationStarted() {
+    public void onQuickStepStarted() {
         boolean alreadySeenRecentsOnboarding = Prefs.getBoolean(mContext,
                 Prefs.Key.HAS_SEEN_RECENTS_ONBOARDING, false);
         if (!alreadySeenRecentsOnboarding) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
index 58adde2..3698c3a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/EmptyShadeView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import android.annotation.ColorInt;
+import android.annotation.StringRes;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.AttributeSet;
@@ -30,6 +31,7 @@
 public class EmptyShadeView extends StackScrollerDecorView {
 
     private TextView mEmptyText;
+    private @StringRes int mText = R.string.empty_shade_text;
 
     public EmptyShadeView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -38,7 +40,7 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        mEmptyText.setText(R.string.empty_shade_text);
+        mEmptyText.setText(mText);
     }
 
     @Override
@@ -50,6 +52,11 @@
         mEmptyText.setTextColor(color);
     }
 
+    public void setText(@StringRes int text) {
+        mText = text;
+        mEmptyText.setText(mText);
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 9fa06f7..c5781d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -175,8 +175,8 @@
         }
 
         @Override
-        public void onRecentsAnimationStarted() {
-            mNavigationBarView.setRecentsAnimationStarted(true);
+        public void onQuickStepStarted() {
+            mNavigationBarView.onQuickStepStarted();
 
             // Use navbar dragging as a signal to hide the rotate button
             setRotateSuggestionButtonState(false);
@@ -343,10 +343,19 @@
             boolean showImeSwitcher) {
         boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
         int hints = mNavigationIconHints;
-        if (imeShown && backDisposition != InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS) {
-            hints |= NAVIGATION_HINT_BACK_ALT;
-        } else {
-            hints &= ~NAVIGATION_HINT_BACK_ALT;
+        switch (backDisposition) {
+            case InputMethodService.BACK_DISPOSITION_DEFAULT:
+            case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
+            case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
+                if (imeShown) {
+                    hints |= NAVIGATION_HINT_BACK_ALT;
+                } else {
+                    hints &= ~NAVIGATION_HINT_BACK_ALT;
+                }
+                break;
+            case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
+                hints &= ~NAVIGATION_HINT_BACK_ALT;
+                break;
         }
         if (showImeSwitcher) {
             hints |= NAVIGATION_HINT_IME_SHOWN;
@@ -751,6 +760,7 @@
         if (shouldDisableNavbarGestures()) {
             return false;
         }
+        mNavigationBarView.onNavigationButtonLongPress(v);
         mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS);
         mAssistManager.startAssist(new Bundle() /* args */);
         mStatusBar.awakenDreams();
@@ -787,10 +797,12 @@
     }
 
     private boolean onLongPressBackHome(View v) {
+        mNavigationBarView.onNavigationButtonLongPress(v);
         return onLongPressNavigationButtons(v, R.id.back, R.id.home);
     }
 
     private boolean onLongPressBackRecents(View v) {
+        mNavigationBarView.onNavigationButtonLongPress(v);
         return onLongPressNavigationButtons(v, R.id.back, R.id.recent_apps);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 6a1ed51..cd000fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -19,31 +19,22 @@
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_TOP;
-import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
-import static com.android.systemui.OverviewProxyService.TAG_OPS;
 
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.Rect;
-import android.os.RemoteException;
-import android.util.Log;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
 import com.android.systemui.Dependency;
-import com.android.systemui.OverviewProxyService;
-import com.android.systemui.OverviewProxyService.OverviewProxyListener;
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
-import com.android.systemui.shared.recents.IOverviewProxy;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.stackdivider.Divider;
 import com.android.systemui.tuner.TunerService;
 
@@ -75,25 +66,14 @@
     private NavigationBarView mNavigationBarView;
     private boolean mIsVertical;
 
-    private final QuickScrubController mQuickScrubController;
+    private final QuickStepController mQuickStepController;
     private final int mScrollTouchSlop;
-    private final Matrix mTransformGlobalMatrix = new Matrix();
-    private final Matrix mTransformLocalMatrix = new Matrix();
     private final StatusBar mStatusBar;
     private int mTouchDownX;
     private int mTouchDownY;
     private boolean mDownOnRecents;
     private VelocityTracker mVelocityTracker;
-    private OverviewProxyService mOverviewProxyService = Dependency.get(OverviewProxyService.class);
-    private final OverviewProxyListener mOverviewProxyListener = new OverviewProxyListener() {
-        @Override
-        public void onRecentsAnimationStarted() {
-            mRecentsAnimationStarted = true;
-            mQuickScrubController.setRecentsAnimationStarted(true /* started */);
-        }
-    };
 
-    private boolean mRecentsAnimationStarted;
     private boolean mDockWindowEnabled;
     private boolean mDockWindowTouchSlopExceeded;
     private int mDragMode;
@@ -103,14 +83,12 @@
         mStatusBar = SysUiServiceProvider.getComponent(context, StatusBar.class);
         Resources r = context.getResources();
         mScrollTouchSlop = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
-        mQuickScrubController = new QuickScrubController(context);
+        mQuickStepController = new QuickStepController(context);
         Dependency.get(TunerService.class).addTunable(this, KEY_DOCK_WINDOW_GESTURE);
-        mOverviewProxyService.addCallback(mOverviewProxyListener);
     }
 
     public void destroy() {
         Dependency.get(TunerService.class).removeTunable(this);
-        mOverviewProxyService.removeCallback(mOverviewProxyListener);
     }
 
     public void setComponents(RecentsComponent recentsComponent, Divider divider,
@@ -118,65 +96,19 @@
         mRecentsComponent = recentsComponent;
         mDivider = divider;
         mNavigationBarView = navigationBarView;
-        mQuickScrubController.setComponents(mNavigationBarView);
+        mQuickStepController.setComponents(mNavigationBarView);
     }
 
     public void setBarState(boolean isVertical, boolean isRTL) {
         mIsVertical = isVertical;
-        mQuickScrubController.setBarState(isVertical, isRTL);
-    }
-
-    private boolean proxyMotionEvents(MotionEvent event) {
-        final IOverviewProxy overviewProxy = mOverviewProxyService.getProxy();
-        if (overviewProxy != null && mNavigationBarView.isQuickStepSwipeUpEnabled()) {
-            mNavigationBarView.requestUnbufferedDispatch(event);
-            event.transform(mTransformGlobalMatrix);
-            try {
-                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
-                    overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
-                }
-                overviewProxy.onMotionEvent(event);
-                if (DEBUG_OVERVIEW_PROXY) {
-                    Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
-                }
-                return true;
-            } catch (RemoteException e) {
-                Log.e(TAG, "Callback failed", e);
-            } finally {
-                event.transform(mTransformLocalMatrix);
-            }
-        }
-        return false;
+        mQuickStepController.setBarState(isVertical, isRTL);
     }
 
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing()
-                || !mStatusBar.isPresenterFullyCollapsed()) {
+        if (!canHandleGestures()) {
             return false;
         }
-
-        int action = event.getActionMasked();
-        switch (action) {
-            case MotionEvent.ACTION_DOWN: {
-                mTouchDownX = (int) event.getX();
-                mTouchDownY = (int) event.getY();
-                mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
-                mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
-                mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
-                mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
-                mRecentsAnimationStarted = false;
-                mQuickScrubController.setRecentsAnimationStarted(false /* started */);
-                break;
-            }
-        }
-        boolean handledByQuickscrub = mQuickScrubController.onInterceptTouchEvent(event);
-        if (!handledByQuickscrub) {
-            // Proxy motion events until we start intercepting for quickscrub
-            proxyMotionEvents(event);
-        }
-
-        boolean result = handledByQuickscrub;
-        result |= mRecentsAnimationStarted;
+        boolean result = mQuickStepController.onInterceptTouchEvent(event);
         if (mDockWindowEnabled) {
             result |= interceptDockWindowEvent(event);
         }
@@ -184,18 +116,10 @@
     }
 
     public boolean onTouchEvent(MotionEvent event) {
-        if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing()
-                || !mStatusBar.isPresenterFullyCollapsed()) {
+        if (!canHandleGestures()) {
             return false;
         }
-
-        // The same down event was just sent on intercept and therefore can be ignored here
-        boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
-                && mOverviewProxyService.getProxy() != null;
-        boolean result = mQuickScrubController.onTouchEvent(event)
-                || ignoreProxyDownEvent
-                || proxyMotionEvents(event);
-        result |= mRecentsAnimationStarted;
+        boolean result = mQuickStepController.onTouchEvent(event);
         if (mDockWindowEnabled) {
             result |= handleDockWindowEvent(event);
         }
@@ -203,17 +127,19 @@
     }
 
     public void onDraw(Canvas canvas) {
-        if (mNavigationBarView.isQuickScrubEnabled()) {
-            mQuickScrubController.onDraw(canvas);
-        }
+        mQuickStepController.onDraw(canvas);
     }
 
     public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        mQuickScrubController.onLayout(changed, left, top, right, bottom);
+        mQuickStepController.onLayout(changed, left, top, right, bottom);
     }
 
     public void onDarkIntensityChange(float intensity) {
-        mQuickScrubController.onDarkIntensityChange(intensity);
+        mQuickStepController.onDarkIntensityChange(intensity);
+    }
+
+    public void onNavigationButtonLongPress(View v) {
+        mQuickStepController.onNavigationButtonLongPress(v);
     }
 
     private boolean interceptDockWindowEvent(MotionEvent event) {
@@ -342,6 +268,11 @@
         mVelocityTracker = null;
     }
 
+    private boolean canHandleGestures() {
+        return !mNavigationBarView.inScreenPinning() && !mStatusBar.isKeyguardShowing()
+                && mStatusBar.isPresenterFullyCollapsed();
+    }
+
     private int calculateDragMode() {
         if (mIsVertical && !mDivider.getView().isHorizontalDivision()) {
             return DRAG_MODE_DIVIDER;
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 e97fa85..fcbd37c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -290,18 +290,12 @@
         notifyVerticalChangedListener(mVertical);
     }
 
-    public void setRecentsAnimationStarted(boolean started) {
+    public void onQuickStepStarted() {
         if (mRecentsOnboarding != null) {
-            mRecentsOnboarding.onRecentsAnimationStarted();
+            mRecentsOnboarding.onQuickStepStarted();
         }
     }
 
-    public void onConnectionChanged(boolean isConnected) {
-        updateSlippery();
-        updateNavButtonIcons();
-        setUpSwipeUpOnboarding(isConnected);
-    }
-
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
         switch (event.getActionMasked()) {
@@ -675,6 +669,10 @@
         }
     }
 
+    public void onNavigationButtonLongPress(View v) {
+        mGestureHelper.onNavigationButtonLongPress(v);
+    }
+
     public void onPanelExpandedChange(boolean expanded) {
         updateSlippery();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
similarity index 65%
rename from packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index 00aff53..19544b1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickScrubController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -25,6 +25,7 @@
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
 import android.graphics.Canvas;
+import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.os.Handler;
@@ -55,10 +56,10 @@
 /**
  * Class to detect gestures on the navigation bar and implement quick scrub and switch.
  */
-public class QuickScrubController extends GestureDetector.SimpleOnGestureListener implements
+public class QuickStepController extends GestureDetector.SimpleOnGestureListener implements
         GestureHelper {
 
-    private static final String TAG = "QuickScrubController";
+    private static final String TAG = "QuickStepController";
     private static final int QUICK_SWITCH_FLING_VELOCITY = 0;
     private static final int ANIM_DURATION_MS = 200;
     private static final long LONG_PRESS_DELAY_MS = 225;
@@ -75,7 +76,8 @@
     private boolean mDraggingActive;
     private boolean mQuickScrubActive;
     private boolean mAllowQuickSwitch;
-    private boolean mRecentsAnimationStarted;
+    private boolean mAllowGestureDetection;
+    private boolean mQuickStepStarted;
     private float mDownOffset;
     private float mTranslation;
     private int mTouchDownX;
@@ -101,6 +103,8 @@
     private final ValueAnimator mButtonAnimator;
     private final AnimatorSet mQuickScrubEndAnimator;
     private final Context mContext;
+    private final Matrix mTransformGlobalMatrix = new Matrix();
+    private final Matrix mTransformLocalMatrix = new Matrix();
     private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
 
     private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> {
@@ -123,7 +127,6 @@
     private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            mNavigationBarView.getHomeButton().setClickable(true);
             mQuickScrubActive = false;
             mTranslation = 0;
             mQuickScrubEndAnimator.setCurrentPlayTime(mQuickScrubEndAnimator.getDuration());
@@ -165,7 +168,7 @@
             }
         };
 
-    public QuickScrubController(Context context) {
+    public QuickStepController(Context context) {
         mContext = context;
         mScrollTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mOverviewEventSender = Dependency.get(OverviewProxyService.class);
@@ -197,31 +200,35 @@
      */
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
-        final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
-        if (!mNavigationBarView.isQuickScrubEnabled()) {
-            homeButton.setDelayTouchFeedback(false);
-            return false;
-        }
-
         return handleTouchEvent(event);
     }
 
     /**
-     * @return true if we want to handle touch events for quick scrub/switch and prevent proxying
-     *         the event to the overview service.
+     * @return true if we want to handle touch events for quick scrub/switch or if down event (that
+     *         will get consumed and ignored). No events will be proxied to the overview service.
      */
     @Override
     public boolean onTouchEvent(MotionEvent event) {
-        return handleTouchEvent(event);
+        // The same down event was just sent on intercept and therefore can be ignored here
+        final boolean ignoreProxyDownEvent = event.getAction() == MotionEvent.ACTION_DOWN
+                && mOverviewEventSender.getProxy() != null;
+        return ignoreProxyDownEvent || handleTouchEvent(event);
     }
 
     private boolean handleTouchEvent(MotionEvent event) {
-        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+        if (!mNavigationBarView.isQuickScrubEnabled()
+                && !mNavigationBarView.isQuickStepSwipeUpEnabled()) {
+            mNavigationBarView.getHomeButton().setDelayTouchFeedback(false /* delay */);
+            return false;
+        }
+        mNavigationBarView.requestUnbufferedDispatch(event);
+
         final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
         if (mGestureDetector.onTouchEvent(event)) {
             // If the fling has been handled on UP, then skip proxying the UP
             return true;
         }
+        final boolean homePressed = mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME;
         int action = event.getAction();
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_DOWN: {
@@ -232,89 +239,99 @@
                     mQuickScrubEndAnimator.end();
                 }
                 mHomeButtonView = homeButton.getCurrentView();
-                if (mNavigationBarView.isQuickScrubEnabled()
-                        && mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME) {
-                    mTouchDownX = x;
-                    mTouchDownY = y;
-                    homeButton.setDelayTouchFeedback(true);
+                homeButton.setDelayTouchFeedback(true /* delay */);
+                mTouchDownX = x;
+                mTouchDownY = y;
+                if (homePressed) {
                     mHandler.postDelayed(mLongPressRunnable, LONG_PRESS_DELAY_MS);
-                } else {
-                    homeButton.setDelayTouchFeedback(false);
-                    mTouchDownX = mTouchDownY = -1;
                 }
+                mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
+                mTransformLocalMatrix.set(Matrix.IDENTITY_MATRIX);
+                mNavigationBarView.transformMatrixToGlobal(mTransformGlobalMatrix);
+                mNavigationBarView.transformMatrixToLocal(mTransformLocalMatrix);
+                mQuickStepStarted = false;
                 mAllowQuickSwitch = true;
+                mAllowGestureDetection = true;
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                if (mTouchDownX != -1) {
-                    int x = (int) event.getX();
-                    int y = (int) event.getY();
-                    int xDiff = Math.abs(x - mTouchDownX);
-                    int yDiff = Math.abs(y - mTouchDownY);
-                    boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff;
-                    boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff;
-                    boolean exceededTouchSlop, exceededPerpendicularTouchSlop;
-                    int pos, touchDown, offset, trackSize;
+                if (mQuickStepStarted || !mAllowGestureDetection){
+                    break;
+                }
+                int x = (int) event.getX();
+                int y = (int) event.getY();
+                int xDiff = Math.abs(x - mTouchDownX);
+                int yDiff = Math.abs(y - mTouchDownY);
+                boolean exceededTouchSlopX = xDiff > mScrollTouchSlop && xDiff > yDiff;
+                boolean exceededTouchSlopY = yDiff > mScrollTouchSlop && yDiff > xDiff;
+                boolean exceededTouchSlop, exceededPerpendicularTouchSlop;
+                int pos, touchDown, offset, trackSize;
 
-                    if (mIsVertical) {
-                        exceededTouchSlop = exceededTouchSlopY;
-                        exceededPerpendicularTouchSlop = exceededTouchSlopX;
-                        pos = y;
-                        touchDown = mTouchDownY;
-                        offset = pos - mTrackRect.top;
-                        trackSize = mTrackRect.height();
-                    } else {
-                        exceededTouchSlop = exceededTouchSlopX;
-                        exceededPerpendicularTouchSlop = exceededTouchSlopY;
-                        pos = x;
-                        touchDown = mTouchDownX;
-                        offset = pos - mTrackRect.left;
-                        trackSize = mTrackRect.width();
+                if (mIsVertical) {
+                    exceededTouchSlop = exceededTouchSlopY;
+                    exceededPerpendicularTouchSlop = exceededTouchSlopX;
+                    pos = y;
+                    touchDown = mTouchDownY;
+                    offset = pos - mTrackRect.top;
+                    trackSize = mTrackRect.height();
+                } else {
+                    exceededTouchSlop = exceededTouchSlopX;
+                    exceededPerpendicularTouchSlop = exceededTouchSlopY;
+                    pos = x;
+                    touchDown = mTouchDownX;
+                    offset = pos - mTrackRect.left;
+                    trackSize = mTrackRect.width();
+                }
+                // Decide to start quickstep if dragging away from the navigation bar, otherwise in
+                // the parallel direction, decide to start quickscrub. Only one may run.
+                if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) {
+                    if (mNavigationBarView.isQuickStepSwipeUpEnabled()) {
+                        startQuickStep(event);
                     }
-                    // Do not start scrubbing when dragging in the perpendicular direction if we
-                    // haven't already started quickscrub
-                    if (!mDraggingActive && !mQuickScrubActive && exceededPerpendicularTouchSlop) {
-                        mHandler.removeCallbacksAndMessages(null);
-                        return false;
-                    }
-                    if (!mDragPositive) {
-                        offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
-                    }
+                    break;
+                }
 
-                    // Control the button movement
-                    if (!mDraggingActive && exceededTouchSlop && !mRecentsAnimationStarted) {
-                        boolean allowDrag = !mDragPositive
-                                ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
-                        if (allowDrag) {
-                            mDownOffset = offset;
-                            homeButton.setClickable(false);
-                            mDraggingActive = true;
-                        }
+                // Do not handle quick scrub/switch if disabled or hit target is not home button
+                if (!homePressed || !mNavigationBarView.isQuickScrubEnabled()) {
+                    break;
+                }
+
+                if (!mDragPositive) {
+                    offset -= mIsVertical ? mTrackRect.height() : mTrackRect.width();
+                }
+
+                // Control the button movement
+                if (!mDraggingActive && exceededTouchSlop) {
+                    boolean allowDrag = !mDragPositive
+                            ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
+                    if (allowDrag) {
+                        mDownOffset = offset;
+                        homeButton.abortCurrentGesture();
+                        mDraggingActive = true;
                     }
-                    if (mDraggingActive && (mDragPositive && offset >= 0
-                            || !mDragPositive && offset <= 0)) {
-                        float scrubFraction =
-                                Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
-                        mTranslation = !mDragPositive
-                            ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
-                            : Utilities.clamp(offset - mDownOffset, 0, trackSize);
-                        if (mQuickScrubActive) {
-                            try {
-                                mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
-                                if (DEBUG_OVERVIEW_PROXY) {
-                                    Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
-                                }
-                            } catch (RemoteException e) {
-                                Log.e(TAG, "Failed to send progress of quick scrub.", e);
+                }
+                if (mDraggingActive && (mDragPositive && offset >= 0
+                        || !mDragPositive && offset <= 0)) {
+                    float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
+                    mTranslation = !mDragPositive
+                        ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
+                        : Utilities.clamp(offset - mDownOffset, 0, trackSize);
+                    if (mQuickScrubActive) {
+                        try {
+                            mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
+                            if (DEBUG_OVERVIEW_PROXY) {
+                                Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
                             }
-                        } else {
-                            mTranslation /= SWITCH_STICKINESS;
+                        } catch (RemoteException e) {
+                            Log.e(TAG, "Failed to send progress of quick scrub.", e);
                         }
-                        if (mIsVertical) {
-                            mHomeButtonView.setTranslationY(mTranslation);
-                        } else {
-                            mHomeButtonView.setTranslationX(mTranslation);
-                        }
+                    } else {
+                        mTranslation /= SWITCH_STICKINESS;
+                    }
+                    if (mIsVertical) {
+                        mHomeButtonView.setTranslationY(mTranslation);
+                    } else {
+                        mHomeButtonView.setTranslationX(mTranslation);
                     }
                 }
                 break;
@@ -324,11 +341,20 @@
                 endQuickScrub(true /* animate */);
                 break;
         }
-        return mDraggingActive || mQuickScrubActive;
+
+        // Proxy motion events to launcher if not handled by quick scrub/switch
+        boolean handled = mDraggingActive || mQuickScrubActive;
+        if (!handled && mAllowGestureDetection) {
+            proxyMotionEvents(event);
+        }
+        return handled || mQuickStepStarted;
     }
 
     @Override
     public void onDraw(Canvas canvas) {
+        if (mNavigationBarView.isQuickScrubEnabled()) {
+            return;
+        }
         int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
                 mDarkTrackColor);
         mTrackPaint.setColor(color);
@@ -381,6 +407,31 @@
         }
     }
 
+    @Override
+    public void onNavigationButtonLongPress(View v) {
+        mAllowGestureDetection = false;
+        mHandler.removeCallbacksAndMessages(null);
+    }
+
+    private void startQuickStep(MotionEvent event) {
+        mQuickStepStarted = true;
+        event.transform(mTransformGlobalMatrix);
+        try {
+            mOverviewEventSender.getProxy().onQuickStep(event);
+            if (DEBUG_OVERVIEW_PROXY) {
+                Log.d(TAG_OPS, "Quick Step Start");
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed to send quick step started.", e);
+        } finally {
+            event.transform(mTransformLocalMatrix);
+        }
+        mOverviewEventSender.notifyQuickStepStarted();
+        mNavigationBarView.getHomeButton().abortCurrentGesture();
+        cancelQuickSwitch();
+        mHandler.removeCallbacksAndMessages(null);
+    }
+
     private void startQuickScrub() {
         if (!mQuickScrubActive && mDraggingActive) {
             mQuickScrubActive = true;
@@ -396,9 +447,6 @@
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to send start of quick scrub.", e);
             }
-        } else {
-            // After long press do not allow quick scrub/switch
-            mTouchDownX = -1;
         }
     }
 
@@ -421,11 +469,24 @@
         mDraggingActive = false;
     }
 
-    public void setRecentsAnimationStarted(boolean started) {
-        mRecentsAnimationStarted = started;
-        if (started) {
-            cancelQuickSwitch();
+    private boolean proxyMotionEvents(MotionEvent event) {
+        final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+        event.transform(mTransformGlobalMatrix);
+        try {
+            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
+                overviewProxy.onPreMotionEvent(mNavigationBarView.getDownHitTarget());
+            }
+            overviewProxy.onMotionEvent(event);
+            if (DEBUG_OVERVIEW_PROXY) {
+                Log.d(TAG_OPS, "Send MotionEvent: " + event.toString());
+            }
+            return true;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Callback failed", e);
+        } finally {
+            event.transform(mTransformLocalMatrix);
         }
+        return false;
     }
 
     public void cancelQuickSwitch() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index e4f142a..2e45b12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -232,6 +232,7 @@
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.util.NotificationChannels;
 import com.android.systemui.volume.VolumeComponent;
@@ -407,6 +408,7 @@
     protected NotificationEntryManager mEntryManager;
     protected NotificationViewHierarchyManager mViewHierarchyManager;
     protected AppOpsListener mAppOpsListener;
+    private ZenModeController mZenController;
 
     /**
      * Helper that is responsible for showing the right toast when a disallowed activity operation
@@ -626,6 +628,7 @@
         mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
         mAppOpsListener = Dependency.get(AppOpsListener.class);
         mAppOpsListener.setUpWithPresenter(this, mEntryManager);
+        mZenController = Dependency.get(ZenModeController.class);
 
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
         mColorExtractor.addOnColorsChangedListener(this);
@@ -1166,6 +1169,7 @@
         }
         mEmptyShadeView = (EmptyShadeView) LayoutInflater.from(mContext).inflate(
                 R.layout.status_bar_no_notifications, mStackScroller, false);
+        mEmptyShadeView.setText(R.string.empty_shade_text);
         mStackScroller.setEmptyShadeView(mEmptyShadeView);
     }
 
@@ -1498,6 +1502,9 @@
         return entry.row.getParent() instanceof NotificationStackScrollLayout;
     }
 
+    public boolean areNotificationsHidden() {
+        return mZenController.areNotificationsHiddenInShade();
+    }
 
     public void requestNotificationUpdate() {
         mEntryManager.updateNotifications();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 3bcfd4b..e5fefd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -224,8 +224,10 @@
             case MotionEvent.ACTION_DOWN:
                 mDownTime = SystemClock.uptimeMillis();
                 mLongClicked = false;
-                mTouchDownX = (int) ev.getX();
-                mTouchDownY = (int) ev.getY();
+
+                // Use raw X and Y to detect gestures in case a parent changes the x and y values
+                mTouchDownX = (int) ev.getRawX();
+                mTouchDownY = (int) ev.getRawY();
                 if (mCode != 0) {
                     sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);
                 } else {
@@ -241,8 +243,8 @@
                 postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());
                 break;
             case MotionEvent.ACTION_MOVE:
-                x = (int)ev.getX();
-                y = (int)ev.getY();
+                x = (int)ev.getRawX();
+                y = (int)ev.getRawY();
                 boolean exceededTouchSlopX = Math.abs(x - mTouchDownX) > mTouchSlop;
                 boolean exceededTouchSlopY = Math.abs(y - mTouchDownY) > mTouchSlop;
                 if (exceededTouchSlopX || exceededTouchSlopY) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 8777aa6..4ee8059 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -35,6 +35,7 @@
     boolean isCountdownConditionSupported();
     int getCurrentUser();
     boolean isVolumeRestricted();
+    boolean areNotificationsHiddenInShade();
 
     public static interface Callback {
         default void onZenChanged(int zen) {}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index 0fd2445..a9da239 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -33,13 +33,11 @@
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
 import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
 import android.service.notification.ZenModeConfig;
 import android.service.notification.ZenModeConfig.ZenRule;
-import android.support.annotation.VisibleForTesting;
 import android.util.Log;
-import android.util.Slog;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.settings.CurrentUserTracker;
 import com.android.systemui.util.Utils;
@@ -64,9 +62,9 @@
     private final UserManager mUserManager;
 
     private int mUserId;
-    private boolean mRequesting;
     private boolean mRegistered;
     private ZenModeConfig mConfig;
+    private int mZenMode;
 
     public ZenModeControllerImpl(Context context, Handler handler) {
         super(context);
@@ -74,6 +72,7 @@
         mModeSetting = new GlobalSetting(mContext, handler, Global.ZEN_MODE) {
             @Override
             protected void handleValueChanged(int value) {
+                updateZenMode(value);
                 fireZenChanged(value);
             }
         };
@@ -86,7 +85,9 @@
         mNoMan = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
         mConfig = mNoMan.getZenModeConfig();
         mModeSetting.setListening(true);
+        updateZenMode(mModeSetting.getValue());
         mConfigSetting.setListening(true);
+        updateZenModeConfig();
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
         mSetupObserver = new SetupObserver(handler);
         mSetupObserver.register();
@@ -101,6 +102,15 @@
     }
 
     @Override
+    public boolean areNotificationsHiddenInShade() {
+        if (mZenMode != Global.ZEN_MODE_OFF) {
+            return (mConfig.suppressedVisualEffects & NotificationManager.Policy
+                    .SUPPRESSED_EFFECT_NOTIFICATION_LIST) != 0;
+        }
+        return false;
+    }
+
+    @Override
     public void addCallback(Callback callback) {
         mCallbacks.add(callback);
     }
@@ -186,10 +196,6 @@
         Utils.safeForeach(mCallbacks, c -> c.onZenAvailableChanged(available));
     }
 
-    private void fireConditionsChanged(Condition[] conditions) {
-        Utils.safeForeach(mCallbacks, c -> c.onConditionsChanged(conditions));
-    }
-
     private void fireManualRuleChanged(ZenRule rule) {
         Utils.safeForeach(mCallbacks, c -> c.onManualRuleChanged(rule));
     }
@@ -199,17 +205,13 @@
         Utils.safeForeach(mCallbacks, c -> c.onConfigChanged(config));
     }
 
-    private void updateConditions(Condition[] conditions) {
-        if (conditions == null || conditions.length == 0) return;
-        for (Condition c : conditions) {
-            if ((c.flags & Condition.FLAG_RELEVANT_NOW) == 0) continue;
-            mConditions.put(c.id, c);
-        }
-        fireConditionsChanged(
-                mConditions.values().toArray(new Condition[mConditions.values().size()]));
+    @VisibleForTesting
+    protected void updateZenMode(int mode) {
+        mZenMode = mode;
     }
 
-    private void updateZenModeConfig() {
+    @VisibleForTesting
+    protected void updateZenModeConfig() {
         final ZenModeConfig config = mNoMan.getZenModeConfig();
         if (Objects.equals(config, mConfig)) return;
         final ZenRule oldRule = mConfig != null ? mConfig.manualRule : null;
@@ -220,16 +222,6 @@
         fireManualRuleChanged(newRule);
     }
 
-    private final IConditionListener mListener = new IConditionListener.Stub() {
-        @Override
-        public void onConditionsReceived(Condition[] conditions) {
-            if (DEBUG) Slog.d(TAG, "onConditionsReceived "
-                    + (conditions == null ? 0 : conditions.length) + " mRequesting=" + mRequesting);
-            if (!mRequesting) return;
-            updateConditions(conditions);
-        }
-    };
-
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 66fde79..a85f4e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -104,7 +104,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
@@ -3985,6 +3984,11 @@
                 } else {
                     mEmptyShadeView.setInvisible();
                 }
+                if (mStatusBar.areNotificationsHidden()) {
+                    mEmptyShadeView.setText(R.string.dnd_suppressing_shade_text);
+                } else {
+                    mEmptyShadeView.setText(R.string.empty_shade_text);
+                }
                 mEmptyShadeView.setVisibility(newVisibility);
                 mEmptyShadeView.setWillBeGone(false);
                 updateContentHeight();
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 91314fe..e94d6bd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -897,6 +897,9 @@
     }
 
     private String getStreamLabelH(StreamState ss) {
+        if (ss == null) {
+            return "";
+        }
         if (ss.remoteLabel != null) {
             return ss.remoteLabel;
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
index ec994a1..5c34730 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/IconLoggerImplTest.java
@@ -17,7 +17,7 @@
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_NUM_STATUS_ICONS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.FIELD_STATUS_ICONS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent
-        .NOTIFICATION_SINCE_CREATE_MILLIS;
+        .RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS;
 
 import static org.junit.Assert.*;
 import static org.mockito.ArgumentMatchers.any;
@@ -119,9 +119,9 @@
 
         verify(mMetricsLogger).write(argThat(maker -> {
             if (IconLoggerImpl.MIN_LOG_INTERVAL >
-                    (long) maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS)) {
+                    (long) maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS)) {
                 Log.e("IconLoggerImplTest", "Invalid latency "
-                        + maker.getTaggedData(NOTIFICATION_SINCE_CREATE_MILLIS));
+                        + maker.getTaggedData(RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS));
                 return false;
             }
             if (1 != (int) maker.getTaggedData(FIELD_NUM_STATUS_ICONS)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
index 8124bf39..da8017e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/ZenModeControllerImplTest.java
@@ -14,11 +14,17 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
+import android.app.NotificationManager;
 import android.os.Handler;
+import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -27,8 +33,11 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.ZenModeController.Callback;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
@@ -36,21 +45,64 @@
 public class ZenModeControllerImplTest extends SysuiTestCase {
 
     private Callback mCallback;
+    @Mock
+    NotificationManager mNm;
+    @Mock
+    ZenModeConfig mConfig;
+
+    private ZenModeControllerImpl mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext.addMockSystemService(NotificationManager.class, mNm);
+        when(mNm.getZenModeConfig()).thenReturn(mConfig);
+
+        mController = new ZenModeControllerImpl(mContext, new Handler());
+    }
 
     @Test
     public void testRemoveDuringCallback() {
-        ZenModeControllerImpl controller = new ZenModeControllerImpl(mContext, new Handler());
         mCallback = new Callback() {
             @Override
             public void onConfigChanged(ZenModeConfig config) {
-                controller.removeCallback(mCallback);
+                mController.removeCallback(mCallback);
             }
         };
-        controller.addCallback(mCallback);
+        mController.addCallback(mCallback);
         Callback mockCallback = mock(Callback.class);
-        controller.addCallback(mockCallback);
-        controller.fireConfigChanged(null);
+        mController.addCallback(mockCallback);
+        mController.fireConfigChanged(null);
         verify(mockCallback).onConfigChanged(eq(null));
     }
 
+    @Test
+    public void testAreNotificationsHiddenInShade_zenOffShadeSuppressed() {
+        mConfig.suppressedVisualEffects =
+                NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+        mController.updateZenMode(Settings.Global.ZEN_MODE_OFF);
+        mController.updateZenModeConfig();
+
+        assertFalse(mController.areNotificationsHiddenInShade());
+    }
+
+    @Test
+    public void testAreNotificationsHiddenInShade_zenOnShadeNotSuppressed() {
+        mConfig.suppressedVisualEffects =
+                NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+        mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        mController.updateZenModeConfig();
+
+        assertFalse(mController.areNotificationsHiddenInShade());
+    }
+
+    @Test
+    public void testAreNotificationsHiddenInShade_zenOnShadeSuppressed() {
+        mConfig.suppressedVisualEffects =
+                NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+        mController.updateZenMode(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
+        mController.updateZenModeConfig();
+
+        assertTrue(mController.areNotificationsHiddenInShade());
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
index d9673d3..6fa91ff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayoutTest.java
@@ -17,17 +17,16 @@
 package com.android.systemui.statusbar.stack;
 
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import android.annotation.UiThread;
 import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
-import android.view.NotificationHeaderView;
-import android.view.View;
 
+import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.NotificationTestHelper;
+import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.phone.ScrimController;
 import com.android.systemui.statusbar.phone.StatusBar;
@@ -72,4 +71,27 @@
                 0.01 /* delta */);
     }
 
+    @Test
+    public void updateEmptyView_dndSuppressing() {
+        EmptyShadeView view = mock(EmptyShadeView.class);
+        mStackScroller.setEmptyShadeView(view);
+        when(view.willBeGone()).thenReturn(true);
+        when(mBar.areNotificationsHidden()).thenReturn(true);
+
+        mStackScroller.updateEmptyShadeView(true);
+
+        verify(view).setText(R.string.dnd_suppressing_shade_text);
+    }
+
+    @Test
+    public void updateEmptyView_dndNotSuppressing() {
+        EmptyShadeView view = mock(EmptyShadeView.class);
+        mStackScroller.setEmptyShadeView(view);
+        when(view.willBeGone()).thenReturn(true);
+        when(mBar.areNotificationsHidden()).thenReturn(false);
+
+        mStackScroller.updateEmptyShadeView(true);
+
+        verify(view).setText(R.string.empty_shade_text);
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
index fb9bf7a..86c43c9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/leaks/FakeZenModeController.java
@@ -77,4 +77,9 @@
     public boolean isVolumeRestricted() {
         return false;
     }
+
+    @Override
+    public boolean areNotificationsHiddenInShade() {
+        return false;
+    }
 }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index d89cc96..e3be5d4 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5503,6 +5503,10 @@
     // OS: P
     ACTION_MANAGE_NOTIFICATIONS = 1358;
 
+    // This value should never appear in log outputs - it is reserved for
+    // internal platform metrics use.
+    RESERVED_FOR_LOGBUILDER_LATENCY_MILLIS = 1359;
+
     // ---- End P Constants, all P constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index b6e2dca..d6f6c6c 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1398,7 +1398,7 @@
     // Returns the set of all applications that define an android:backupAgent attribute
     private List<PackageInfo> allAgentPackages() {
         // !!! TODO: cache this and regenerate only when necessary
-        int flags = PackageManager.GET_SIGNATURES;
+        int flags = PackageManager.GET_SIGNING_CERTIFICATES;
         List<PackageInfo> packages = mPackageManager.getInstalledPackages(flags);
         int N = packages.size();
         for (int a = N - 1; a >= 0; a--) {
@@ -1643,7 +1643,7 @@
             }
             try {
                 PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
-                        PackageManager.GET_SIGNATURES);
+                        PackageManager.GET_SIGNING_CERTIFICATES);
                 if (!AppBackupUtils.appIsEligibleForBackup(packageInfo.applicationInfo,
                         mPackageManager)) {
                     BackupObserverUtils.sendBackupOnPackageResult(observer, packageName,
@@ -2353,7 +2353,8 @@
         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
         PackageInfo info;
         try {
-            info = mPackageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+            info = mPackageManager.getPackageInfo(packageName,
+                    PackageManager.GET_SIGNING_CERTIFICATES);
         } catch (NameNotFoundException e) {
             Slog.d(TAG, "No such package '" + packageName + "' - not clearing backup data");
             return;
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 3cf374f..dc28cd1 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -23,6 +23,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ResolveInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
@@ -30,6 +31,7 @@
 import android.os.ParcelFileDescriptor;
 import android.util.Slog;
 
+import com.android.server.LocalServices;
 import com.android.server.backup.utils.AppBackupUtils;
 
 import java.io.BufferedInputStream;
@@ -154,7 +156,7 @@
 
     public static List<PackageInfo> getStorableApplications(PackageManager pm) {
         List<PackageInfo> pkgs;
-        pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
+        pkgs = pm.getInstalledPackages(PackageManager.GET_SIGNING_CERTIFICATES);
         int N = pkgs.size();
         for (int a = N-1; a >= 0; a--) {
             PackageInfo pkg = pkgs.get(a);
@@ -235,10 +237,17 @@
         if (home != null) {
             try {
                 homeInfo = mPackageManager.getPackageInfo(home.getPackageName(),
-                        PackageManager.GET_SIGNATURES);
+                        PackageManager.GET_SIGNING_CERTIFICATES);
                 homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
                 homeVersion = homeInfo.getLongVersionCode();
-                homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures);
+                Signature[][] signingHistory = homeInfo.signingCertificateHistory;
+                if (signingHistory == null || signingHistory.length == 0) {
+                    Slog.e(TAG, "Home app has no signing history");
+                } else {
+                    // retrieve the newest sigs to back up
+                    Signature[] homeInfoSignatures = signingHistory[signingHistory.length - 1];
+                    homeSigHashes = BackupUtils.hashSignatureArray(homeInfoSignatures);
+                }
             } catch (NameNotFoundException e) {
                 Slog.w(TAG, "Can't access preferred home info");
                 // proceed as though there were no preferred home set
@@ -252,10 +261,11 @@
             //    2. the home app [or absence] we now use differs from the prior state,
             // OR 3. it looks like we use the same home app + version as before, but
             //       the signatures don't match so we treat them as different apps.
+            PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
             final boolean needHomeBackup = (homeVersion != mStoredHomeVersion)
                     || !Objects.equals(home, mStoredHomeComponent)
                     || (home != null
-                        && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo));
+                        && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo, pmi));
             if (needHomeBackup) {
                 if (DEBUG) {
                     Slog.i(TAG, "Home preference changed; backing up new state " + home);
@@ -304,7 +314,7 @@
                     PackageInfo info = null;
                     try {
                         info = mPackageManager.getPackageInfo(packName,
-                                PackageManager.GET_SIGNATURES);
+                                PackageManager.GET_SIGNING_CERTIFICATES);
                     } catch (NameNotFoundException e) {
                         // Weird; we just found it, and now are told it doesn't exist.
                         // Treat it as having been removed from the device.
@@ -323,9 +333,9 @@
                             continue;
                         }
                     }
-                    
-                    if (info.signatures == null || info.signatures.length == 0)
-                    {
+
+                    Signature[][] signingHistory = info.signingCertificateHistory;
+                    if (signingHistory == null || signingHistory.length == 0) {
                         Slog.w(TAG, "Not backing up package " + packName
                                 + " since it appears to have no signatures.");
                         continue;
@@ -347,8 +357,10 @@
                     } else {
                         outputBufferStream.writeInt(info.versionCode);
                     }
+                    // retrieve the newest sigs to back up
+                    Signature[] infoSignatures = signingHistory[signingHistory.length - 1];
                     writeSignatureHashArray(outputBufferStream,
-                            BackupUtils.hashSignatureArray(info.signatures));
+                            BackupUtils.hashSignatureArray(infoSignatures));
 
                     if (DEBUG) {
                         Slog.v(TAG, "+ writing metadata for " + packName
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
index 2e2d3eb..821cca1 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformAdbBackupTask.java
@@ -129,7 +129,7 @@
                 try {
                     PackageInfo info = backupManagerService.getPackageManager().getPackageInfo(
                             pkgName,
-                            PackageManager.GET_SIGNATURES);
+                            PackageManager.GET_SIGNING_CERTIFICATES);
                     set.put(pkgName, info);
                 } catch (NameNotFoundException e) {
                     Slog.w(TAG, "Unknown package " + pkgName + ", skipping");
@@ -240,7 +240,8 @@
 
         // doAllApps supersedes the package set if any
         if (mAllApps) {
-            List<PackageInfo> allPackages = pm.getInstalledPackages(PackageManager.GET_SIGNATURES);
+            List<PackageInfo> allPackages = pm.getInstalledPackages(
+                    PackageManager.GET_SIGNING_CERTIFICATES);
             for (int i = 0; i < allPackages.size(); i++) {
                 PackageInfo pkg = allPackages.get(i);
                 // Exclude system apps if we've been asked to do so
diff --git a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
index f9c36699..2c2dd85 100644
--- a/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
+++ b/services/backup/java/com/android/server/backup/fullbackup/PerformFullTransportBackupTask.java
@@ -181,7 +181,7 @@
         for (String pkg : whichPackages) {
             try {
                 PackageManager pm = backupManagerService.getPackageManager();
-                PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES);
+                PackageInfo info = pm.getPackageInfo(pkg, PackageManager.GET_SIGNING_CERTIFICATES);
                 mCurrentPackage = info;
                 if (!AppBackupUtils.appIsEligibleForBackup(info.applicationInfo, pm)) {
                     // Cull any packages that have indicated that backups are not permitted,
diff --git a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
index 0ba83cf..11394e66 100644
--- a/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
+++ b/services/backup/java/com/android/server/backup/internal/PerformBackupTask.java
@@ -422,7 +422,8 @@
         // package's backup agent.
         try {
             PackageManager pm = backupManagerService.getPackageManager();
-            mCurrentPackage = pm.getPackageInfo(request.packageName, PackageManager.GET_SIGNATURES);
+            mCurrentPackage = pm.getPackageInfo(request.packageName,
+                    PackageManager.GET_SIGNING_CERTIFICATES);
             if (!AppBackupUtils.appIsEligibleForBackup(mCurrentPackage.applicationInfo, pm)) {
                 // The manifest has changed but we had a stale backup request pending.
                 // This won't happen again because the app won't be requesting further
diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
index 0ca4f25..c1a1c1d 100644
--- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
+++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java
@@ -36,11 +36,13 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
 import android.util.Slog;
 
+import com.android.server.LocalServices;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.FileMetadata;
 import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -207,8 +209,11 @@
                 if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
                     Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
                             info);
+                    PackageManagerInternal pmi = LocalServices.getService(
+                            PackageManagerInternal.class);
                     RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
-                            mBackupManagerService.getPackageManager(), allowApks, info, signatures);
+                            mBackupManagerService.getPackageManager(), allowApks, info, signatures,
+                            pmi);
                     mManifestSignatures.put(info.packageName, signatures);
                     mPackagePolicies.put(pkg, restorePolicy);
                     mPackageInstallers.put(pkg, info.installerPackageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
index e576b3c..dacde0b 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java
@@ -40,6 +40,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
@@ -47,6 +48,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.FileMetadata;
 import com.android.server.backup.KeyValueAdbRestoreEngine;
@@ -470,9 +472,11 @@
                 if (info.path.equals(BACKUP_MANIFEST_FILENAME)) {
                     Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
                             info);
+                    PackageManagerInternal pmi = LocalServices.getService(
+                            PackageManagerInternal.class);
                     RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
                             mBackupManagerService.getPackageManager(), allowApks,
-                            info, signatures);
+                            info, signatures, pmi);
                     mManifestSignatures.put(info.packageName, signatures);
                     mPackagePolicies.put(pkg, restorePolicy);
                     mPackageInstallers.put(pkg, info.installerPackageName);
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index 3caa1e7..4b467e5 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -43,6 +43,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Bundle;
 import android.os.Message;
@@ -57,6 +58,7 @@
 import com.android.internal.backup.IBackupTransport;
 import com.android.server.AppWidgetBackupBridge;
 import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.BackupUtils;
 import com.android.server.backup.PackageManagerBackupAgent;
@@ -504,7 +506,7 @@
 
             try {
                 mCurrentPackage = backupManagerService.getPackageManager().getPackageInfo(
-                        pkgName, PackageManager.GET_SIGNATURES);
+                        pkgName, PackageManager.GET_SIGNING_CERTIFICATES);
             } catch (NameNotFoundException e) {
                 // Whoops, we thought we could restore this package but it
                 // turns out not to be present.  Skip it.
@@ -619,7 +621,8 @@
         }
 
         Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName);
-        if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) {
+        PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage, pmi)) {
             Slog.w(TAG, "Signature mismatch restoring " + packageName);
             mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor,
                     BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage,
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 6780563..5518374 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -25,6 +25,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.os.Process;
 import android.util.Slog;
@@ -37,6 +38,9 @@
  * Utility methods wrapping operations on ApplicationInfo and PackageInfo.
  */
 public class AppBackupUtils {
+
+    private static final boolean DEBUG = false;
+
     /**
      * Returns whether app is eligible for backup.
      *
@@ -88,7 +92,8 @@
     public static boolean appIsRunningAndEligibleForBackupWithTransport(
             @Nullable TransportClient transportClient, String packageName, PackageManager pm) {
         try {
-            PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+            PackageInfo packageInfo = pm.getPackageInfo(packageName,
+                    PackageManager.GET_SIGNING_CERTIFICATES);
             ApplicationInfo applicationInfo = packageInfo.applicationInfo;
             if (!appIsEligibleForBackup(applicationInfo, pm)
                     || appIsStopped(applicationInfo)
@@ -165,13 +170,19 @@
      *
      * <ul>
      *   <li>Source and target have at least one signature each
-     *   <li>Target contains all signatures in source
+     *   <li>Target contains all signatures in source, and nothing more
      * </ul>
      *
+     * or if both source and target have exactly one signature, and they don't match, we check
+     * if the app was ever signed with source signature (i.e. app has rotated key)
+     * Note: key rotation is only supported for apps ever signed with one key, and those apps will
+     * not be allowed to be signed by more certificates in the future
+     *
      * Note that if {@param target} is null we return false.
      */
-    public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
-        if (target == null) {
+    public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target,
+            PackageManagerInternal pmi) {
+        if (target == null || target.packageName == null) {
             return false;
         }
 
@@ -187,33 +198,52 @@
             return true;
         }
 
-        Signature[] deviceSigs = target.signatures;
-        if (MORE_DEBUG) {
-            Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceSigs);
-        }
-
         // Don't allow unsigned apps on either end
-        if (ArrayUtils.isEmpty(storedSigs) || ArrayUtils.isEmpty(deviceSigs)) {
+        if (ArrayUtils.isEmpty(storedSigs)) {
             return false;
         }
 
-        // Signatures can be added over time, so the target-device apk needs to contain all the
-        // source-device apk signatures, but not necessarily the other way around.
-        int nStored = storedSigs.length;
-        int nDevice = deviceSigs.length;
+        Signature[][] deviceHistorySigs = target.signingCertificateHistory;
+        if (ArrayUtils.isEmpty(deviceHistorySigs)) {
+            Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" +
+                    " PackageManager#GET_SIGNING_CERTIFICATES was not specified");
+            return false;
+        }
 
-        for (int i = 0; i < nStored; i++) {
-            boolean match = false;
-            for (int j = 0; j < nDevice; j++) {
-                if (storedSigs[i].equals(deviceSigs[j])) {
-                    match = true;
-                    break;
+        if (DEBUG) {
+            Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceHistorySigs);
+        }
+
+        final int nStored = storedSigs.length;
+        if (nStored == 1) {
+            // if the app is only signed with one sig, it's possible it has rotated its key
+            // (the checks with signing history are delegated to PackageManager)
+            // TODO(b/73988180): address the case that app has declared restoreAnyVersion and is
+            // restoring from higher version to lower after having rotated the key (i.e. higher
+            // version has different sig than lower version that we want to restore to)
+            return pmi.isDataRestoreSafe(storedSigs[0], target.packageName);
+        } else {
+            // the app couldn't have rotated keys, since it was signed with multiple sigs - do
+            // a check to see if we find a match for all stored sigs
+            // since app hasn't rotated key, we only need to check with deviceHistorySigs[0]
+            Signature[] deviceSigs = deviceHistorySigs[0];
+            int nDevice = deviceSigs.length;
+
+            // ensure that each stored sig matches an on-device sig
+            for (int i = 0; i < nStored; i++) {
+                boolean match = false;
+                for (int j = 0; j < nDevice; j++) {
+                    if (storedSigs[i].equals(deviceSigs[j])) {
+                        match = true;
+                        break;
+                    }
+                }
+                if (!match) {
+                    return false;
                 }
             }
-            if (!match) {
-                return false;
-            }
+            // we have found a match for all stored sigs
+            return true;
         }
-        return true;
     }
 }
diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
index d2ab099..994d5a9 100644
--- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
@@ -104,11 +104,16 @@
         printer.println((installerName != null) ? installerName : "");
 
         printer.println(withApk ? "1" : "0");
-        if (pkg.signatures == null) {
+
+        // write the signature block
+        Signature[][] signingHistory = pkg.signingCertificateHistory;
+        if (signingHistory == null) {
             printer.println("0");
         } else {
-            printer.println(Integer.toString(pkg.signatures.length));
-            for (Signature sig : pkg.signatures) {
+            // retrieve the newest sigs to write
+            Signature[] signatures = signingHistory[signingHistory.length - 1];
+            printer.println(Integer.toString(signatures.length));
+            for (Signature sig : signatures) {
                 printer.println(sig.toCharsString());
             }
         }
diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
index 10f0695..df7e6d45 100644
--- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java
@@ -30,6 +30,7 @@
 import android.content.pm.PackageInstaller.Session;
 import android.content.pm.PackageInstaller.SessionParams;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -37,6 +38,7 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.LocalServices;
 import com.android.server.backup.FileMetadata;
 import com.android.server.backup.restore.RestoreDeleteObserver;
 import com.android.server.backup.restore.RestorePolicy;
@@ -142,9 +144,8 @@
                     uninstall = true;
                 } else {
                     try {
-                        PackageInfo pkg = packageManager.getPackageInfo(
-                                info.packageName,
-                                PackageManager.GET_SIGNATURES);
+                        PackageInfo pkg = packageManager.getPackageInfo(info.packageName,
+                                PackageManager.GET_SIGNING_CERTIFICATES);
                         if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP)
                                 == 0) {
                             Slog.w(TAG, "Restore stream contains apk of package "
@@ -154,7 +155,9 @@
                         } else {
                             // So far so good -- do the signatures match the manifest?
                             Signature[] sigs = manifestSignatures.get(info.packageName);
-                            if (AppBackupUtils.signaturesMatch(sigs, pkg)) {
+                            PackageManagerInternal pmi = LocalServices.getService(
+                                    PackageManagerInternal.class);
+                            if (AppBackupUtils.signaturesMatch(sigs, pkg, pmi)) {
                                 // If this is a system-uid app without a declared backup agent,
                                 // don't restore any of the file data.
                                 if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID)
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index cc26ff8..6dd5284 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -50,6 +50,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.os.Bundle;
 import android.os.Process;
@@ -385,7 +386,8 @@
      * @return a restore policy constant.
      */
     public RestorePolicy chooseRestorePolicy(PackageManager packageManager,
-            boolean allowApks, FileMetadata info, Signature[] signatures) {
+            boolean allowApks, FileMetadata info, Signature[] signatures,
+            PackageManagerInternal pmi) {
         if (signatures == null) {
             return RestorePolicy.IGNORE;
         }
@@ -395,7 +397,7 @@
         // Okay, got the manifest info we need...
         try {
             PackageInfo pkgInfo = packageManager.getPackageInfo(
-                    info.packageName, PackageManager.GET_SIGNATURES);
+                    info.packageName, PackageManager.GET_SIGNING_CERTIFICATES);
             // Fall through to IGNORE if the app explicitly disallows backup
             final int flags = pkgInfo.applicationInfo.flags;
             if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) {
@@ -411,7 +413,7 @@
                     // such packages are signed with the platform cert instead of
                     // the app developer's cert, so they're different on every
                     // device.
-                    if (AppBackupUtils.signaturesMatch(signatures, pkgInfo)) {
+                    if (AppBackupUtils.signaturesMatch(signatures, pkgInfo, pmi)) {
                         if ((pkgInfo.applicationInfo.flags
                                 & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) {
                             Slog.i(TAG, "Package has restoreAnyVersion; taking data");
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index ecf80ba..9756d17 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -1346,8 +1346,9 @@
                 return;
             }
             if (!client.mStartedOps.remove(op)) {
-                throw new IllegalStateException("Operation not started: uid" + op.uid
+                Slog.wtf(TAG, "Operation not started: uid" + op.uid
                         + " pkg=" + op.packageName + " op=" + op.op);
+                return;
             }
             finishOperationLocked(op, /*finishNested*/ false);
             if (op.nesting <= 0) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62e82a0..3896871 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -65,7 +65,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.NoSuchElementException;
 
@@ -164,14 +163,9 @@
 
     private int[] mDataActivity;
 
+    // Connection state of default APN type data (i.e. internet) of phones
     private int[] mDataConnectionState;
 
-    private ArrayList<String>[] mConnectedApns;
-
-    private LinkProperties[] mDataConnectionLinkProperties;
-
-    private NetworkCapabilities[] mDataConnectionNetworkCapabilities;
-
     private Bundle[] mCellLocation;
 
     private int[] mDataConnectionNetworkType;
@@ -323,9 +317,8 @@
         mBatteryStats = BatteryStatsService.getService();
 
         int numPhones = TelephonyManager.getDefault().getPhoneCount();
-        if (DBG) log("TelephonyRegistor: ctor numPhones=" + numPhones);
+        if (DBG) log("TelephonyRegistry: ctor numPhones=" + numPhones);
         mNumPhones = numPhones;
-        mConnectedApns = new ArrayList[numPhones];
         mCallState = new int[numPhones];
         mDataActivity = new int[numPhones];
         mDataConnectionState = new int[numPhones];
@@ -339,8 +332,6 @@
         mMessageWaiting = new boolean[numPhones];
         mCallForwarding = new boolean[numPhones];
         mCellLocation = new Bundle[numPhones];
-        mDataConnectionLinkProperties = new LinkProperties[numPhones];
-        mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones];
         mCellInfo = new ArrayList<List<CellInfo>>();
         mPhysicalChannelConfigs = new ArrayList<List<PhysicalChannelConfig>>();
         for (int i = 0; i < numPhones; i++) {
@@ -358,7 +349,6 @@
             mCellLocation[i] = new Bundle();
             mCellInfo.add(i, null);
             mPhysicalChannelConfigs.add(i, null);
-            mConnectedApns[i] = new ArrayList<String>();
         }
 
         // Note that location can be null for non-phone builds like
@@ -1219,36 +1209,12 @@
         int phoneId = SubscriptionManager.getPhoneId(subId);
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
-                boolean modified = false;
-                if (state == TelephonyManager.DATA_CONNECTED) {
-                    if (!mConnectedApns[phoneId].contains(apnType)) {
-                        mConnectedApns[phoneId].add(apnType);
-                        if (mDataConnectionState[phoneId] != state) {
-                            mDataConnectionState[phoneId] = state;
-                            modified = true;
-                        }
-                    }
-                } else {
-                    if (mConnectedApns[phoneId].remove(apnType)) {
-                        if (mConnectedApns[phoneId].isEmpty()) {
-                            mDataConnectionState[phoneId] = state;
-                            modified = true;
-                        } else {
-                            // leave mDataConnectionState as is and
-                            // send out the new status for the APN in question.
-                        }
-                    }
-                }
-                mDataConnectionLinkProperties[phoneId] = linkProperties;
-                mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
-                if (mDataConnectionNetworkType[phoneId] != networkType) {
-                    mDataConnectionNetworkType[phoneId] = networkType;
-                    // need to tell registered listeners about the new network type
-                    modified = true;
-                }
-                if (modified) {
-                    String str = "onDataConnectionStateChanged(" + mDataConnectionState[phoneId]
-                            + ", " + mDataConnectionNetworkType[phoneId] + ")";
+                // We only call the callback when the change is for default APN type.
+                if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)
+                        && (mDataConnectionState[phoneId] != state
+                        || mDataConnectionNetworkType[phoneId] != networkType)) {
+                    String str = "onDataConnectionStateChanged(" + state
+                            + ", " + networkType + ")";
                     log(str);
                     mLocalLog.log(str);
                     for (Record r : mRecords) {
@@ -1259,15 +1225,16 @@
                                 if (DBG) {
                                     log("Notify data connection state changed on sub: " + subId);
                                 }
-                                r.callback.onDataConnectionStateChanged(
-                                        mDataConnectionState[phoneId],
-                                        mDataConnectionNetworkType[phoneId]);
+                                r.callback.onDataConnectionStateChanged(state, networkType);
                             } catch (RemoteException ex) {
                                 mRemoveList.add(r.binder);
                             }
                         }
                     }
                     handleRemoveListLocked();
+
+                    mDataConnectionState[phoneId] = state;
+                    mDataConnectionNetworkType[phoneId] = networkType;
                 }
                 mPreciseDataConnectionState = new PreciseDataConnectionState(state, networkType,
                         apnType, apn, reason, linkProperties, "");
@@ -1503,14 +1470,10 @@
                 pw.println("mCallForwarding=" + mCallForwarding[i]);
                 pw.println("mDataActivity=" + mDataActivity[i]);
                 pw.println("mDataConnectionState=" + mDataConnectionState[i]);
-                pw.println("mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
-                pw.println("mDataConnectionNetworkCapabilities=" +
-                        mDataConnectionNetworkCapabilities[i]);
                 pw.println("mCellLocation=" + mCellLocation[i]);
                 pw.println("mCellInfo=" + mCellInfo.get(i));
                 pw.decreaseIndent();
             }
-            pw.println("mConnectedApns=" + Arrays.toString(mConnectedApns));
             pw.println("mPreciseDataConnectionState=" + mPreciseDataConnectionState);
             pw.println("mPreciseCallState=" + mPreciseCallState);
             pw.println("mCarrierNetworkChangeState=" + mCarrierNetworkChangeState);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 26f83f5..eb4e32e 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -3390,10 +3390,15 @@
                 return;
             }
 
+            app = r.app;
+            if (app != null && app.debugging) {
+                // The app's being debugged; let it ride
+                return;
+            }
+
             if (DEBUG_BACKGROUND_CHECK) {
                 Slog.i(TAG, "Service foreground-required timeout for " + r);
             }
-            app = r.app;
             r.fgWaiting = false;
             stopServiceLocked(r);
         }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4742575..2c4eac0 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4590,7 +4590,7 @@
             }
             ActivityOptions.abort(options);
         } else {
-            updateTransitLocked(TRANSIT_TASK_TO_FRONT, starting, options);
+            updateTransitLocked(TRANSIT_TASK_TO_FRONT, r, options);
         }
         // If a new task is moved to the front, then mark the existing top activity as supporting
         // picture-in-picture while paused only if the task would not be considered an oerlay on top
diff --git a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
index d7d18a9..690d985 100644
--- a/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/GlobalSettingsToPropertiesMapper.java
@@ -43,6 +43,7 @@
         {Settings.Global.FPS_DEVISOR, ThreadedRenderer.DEBUG_FPS_DIVISOR},
         {Settings.Global.DISPLAY_PANEL_LPM, "sys.display_panel_lpm"},
         {Settings.Global.SYS_UIDCPUPOWER, "sys.uidcpupower"},
+        {Settings.Global.SYS_TRACED, "persist.traced.enable"},
     };
 
 
diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java
index e5d564d..d817534 100644
--- a/services/core/java/com/android/server/backup/BackupUtils.java
+++ b/services/core/java/com/android/server/backup/BackupUtils.java
@@ -18,9 +18,12 @@
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
+
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
@@ -30,13 +33,13 @@
 public class BackupUtils {
     private static final String TAG = "BackupUtils";
 
-    private static final boolean DEBUG = false; // STOPSHIP if true
+    private static final boolean DEBUG = false;
 
-    public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target) {
-        if (target == null) {
+    public static boolean signaturesMatch(ArrayList<byte[]> storedSigHashes, PackageInfo target,
+            PackageManagerInternal pmi) {
+        if (target == null || target.packageName == null) {
             return false;
         }
-
         // If the target resides on the system partition, we allow it to restore
         // data from the like-named package in a restore set even if the signatures
         // do not match.  (Unlike general applications, those flashed to the system
@@ -47,48 +50,53 @@
             return true;
         }
 
-        // Allow unsigned apps, but not signed on one device and unsigned on the other
-        // !!! TODO: is this the right policy?
-        Signature[] deviceSigs = target.signatures;
-        if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
-                + " device=" + deviceSigs);
-        if ((storedSigHashes == null || storedSigHashes.size() == 0)
-                && (deviceSigs == null || deviceSigs.length == 0)) {
-            return true;
-        }
-        if (storedSigHashes == null || deviceSigs == null) {
+        // Don't allow unsigned apps on either end
+        if (ArrayUtils.isEmpty(storedSigHashes)) {
             return false;
         }
 
-        // !!! TODO: this demands that every stored signature match one
-        // that is present on device, and does not demand the converse.
-        // Is this this right policy?
-        final int nStored = storedSigHashes.size();
-        final int nDevice = deviceSigs.length;
-
-        // hash each on-device signature
-        ArrayList<byte[]> deviceHashes = new ArrayList<byte[]>(nDevice);
-        for (int i = 0; i < nDevice; i++) {
-            deviceHashes.add(hashSignature(deviceSigs[i]));
+        Signature[][] deviceHistorySigs = target.signingCertificateHistory;
+        if (ArrayUtils.isEmpty(deviceHistorySigs)) {
+            Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" +
+                    " PackageManager#GET_SIGNING_CERTIFICATES was not specified");
+            return false;
         }
 
-        // now ensure that each stored sig (hash) matches an on-device sig (hash)
-        for (int n = 0; n < nStored; n++) {
-            boolean match = false;
-            final byte[] storedHash = storedSigHashes.get(n);
-            for (int i = 0; i < nDevice; i++) {
-                if (Arrays.equals(storedHash, deviceHashes.get(i))) {
-                    match = true;
-                    break;
+        if (DEBUG) {
+            Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes
+                    + " device=" + deviceHistorySigs);
+        }
+
+        final int nStored = storedSigHashes.size();
+        if (nStored == 1) {
+            // if the app is only signed with one sig, it's possible it has rotated its key
+            // the checks with signing history are delegated to PackageManager
+            // TODO(b/73988180): address the case that app has declared restoreAnyVersion and is
+            // restoring from higher version to lower after having rotated the key (i.e. higher
+            // version has different sig than lower version that we want to restore to)
+            return pmi.isDataRestoreSafe(storedSigHashes.get(0), target.packageName);
+        } else {
+            // the app couldn't have rotated keys, since it was signed with multiple sigs - do
+            // a check to see if we find a match for all stored sigs
+            // since app hasn't rotated key, we only need to check with deviceHistorySigs[0]
+            ArrayList<byte[]> deviceHashes = hashSignatureArray(deviceHistorySigs[0]);
+            int nDevice = deviceHashes.size();
+            // ensure that each stored sig matches an on-device sig
+            for (int i = 0; i < nStored; i++) {
+                boolean match = false;
+                for (int j = 0; j < nDevice; j++) {
+                    if (Arrays.equals(storedSigHashes.get(i), deviceHashes.get(j))) {
+                        match = true;
+                        break;
+                    }
+                }
+                if (!match) {
+                    return false;
                 }
             }
-            // match is false when no on-device sig matched one of the stored ones
-            if (!match) {
-                return false;
-            }
+            // we have found a match for all stored sigs
+            return true;
         }
-
-        return true;
     }
 
     public static byte[] hashSignature(byte[] signature) {
diff --git a/services/core/java/com/android/server/display/DisplayDevice.java b/services/core/java/com/android/server/display/DisplayDevice.java
index 3a8e291..2405925 100644
--- a/services/core/java/com/android/server/display/DisplayDevice.java
+++ b/services/core/java/com/android/server/display/DisplayDevice.java
@@ -45,7 +45,7 @@
     private Rect mCurrentDisplayRect;
 
     // The display device owns its surface, but it should only set it
-    // within a transaction from performTraversalInTransactionLocked.
+    // within a transaction from performTraversalLocked.
     private Surface mCurrentSurface;
 
     // DEBUG STATE: Last device info which was written to the log, or null if none.
@@ -122,7 +122,7 @@
     /**
      * Gives the display device a chance to update its properties while in a transaction.
      */
-    public void performTraversalInTransactionLocked() {
+    public void performTraversalLocked(SurfaceControl.Transaction t) {
     }
 
     /**
@@ -140,7 +140,7 @@
     /**
      * Sets the mode, if supported.
      */
-    public void requestDisplayModesInTransactionLocked(int colorMode, int modeId) {
+    public void requestDisplayModesLocked(int colorMode, int modeId) {
     }
 
     public void onOverlayChangedLocked() {
@@ -149,10 +149,10 @@
     /**
      * Sets the display layer stack while in a transaction.
      */
-    public final void setLayerStackInTransactionLocked(int layerStack) {
+    public final void setLayerStackLocked(SurfaceControl.Transaction t, int layerStack) {
         if (mCurrentLayerStack != layerStack) {
             mCurrentLayerStack = layerStack;
-            SurfaceControl.setDisplayLayerStack(mDisplayToken, layerStack);
+            t.setDisplayLayerStack(mDisplayToken, layerStack);
         }
     }
 
@@ -166,7 +166,7 @@
      *            mapped to. displayRect is specified post-orientation, that is
      *            it uses the orientation seen by the end-user
      */
-    public final void setProjectionInTransactionLocked(int orientation,
+    public final void setProjectionLocked(SurfaceControl.Transaction t, int orientation,
             Rect layerStackRect, Rect displayRect) {
         if (mCurrentOrientation != orientation
                 || mCurrentLayerStackRect == null
@@ -185,7 +185,7 @@
             }
             mCurrentDisplayRect.set(displayRect);
 
-            SurfaceControl.setDisplayProjection(mDisplayToken,
+            t.setDisplayProjection(mDisplayToken,
                     orientation, layerStackRect, displayRect);
         }
     }
@@ -193,10 +193,10 @@
     /**
      * Sets the display surface while in a transaction.
      */
-    public final void setSurfaceInTransactionLocked(Surface surface) {
+    public final void setSurfaceLocked(SurfaceControl.Transaction t, Surface surface) {
         if (mCurrentSurface != surface) {
             mCurrentSurface = surface;
-            SurfaceControl.setDisplaySurface(mDisplayToken, surface);
+            t.setDisplaySurface(mDisplayToken, surface);
         }
     }
 
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index a5c1fe2..9861ea7 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -74,6 +74,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import com.android.internal.util.Preconditions;
 import com.android.server.AnimationThread;
@@ -457,14 +458,14 @@
     }
 
     @VisibleForTesting
-    void performTraversalInTransactionFromWindowManagerInternal() {
+    void performTraversalInternal(SurfaceControl.Transaction t) {
         synchronized (mSyncRoot) {
             if (!mPendingTraversal) {
                 return;
             }
             mPendingTraversal = false;
 
-            performTraversalInTransactionLocked();
+            performTraversalLocked(t);
         }
 
         // List is self-synchronized copy-on-write.
@@ -1056,7 +1057,7 @@
         return changed;
     }
 
-    private void performTraversalInTransactionLocked() {
+    private void performTraversalLocked(SurfaceControl.Transaction t) {
         // Clear all viewports before configuring displays so that we can keep
         // track of which ones we have configured.
         clearViewportsLocked();
@@ -1065,8 +1066,8 @@
         final int count = mDisplayDevices.size();
         for (int i = 0; i < count; i++) {
             DisplayDevice device = mDisplayDevices.get(i);
-            configureDisplayInTransactionLocked(device);
-            device.performTraversalInTransactionLocked();
+            configureDisplayLocked(t, device);
+            device.performTraversalLocked(t);
         }
 
         // Tell the input system about these new viewports.
@@ -1150,7 +1151,7 @@
         mVirtualTouchViewports.clear();
     }
 
-    private void configureDisplayInTransactionLocked(DisplayDevice device) {
+    private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) {
         final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
         final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0;
 
@@ -1175,7 +1176,7 @@
                     + device.getDisplayDeviceInfoLocked());
             return;
         }
-        display.configureDisplayInTransactionLocked(device, info.state == Display.STATE_OFF);
+        display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF);
 
         // Update the viewports if needed.
         if (!mDefaultViewport.valid
@@ -1233,7 +1234,7 @@
         mHandler.sendMessage(msg);
     }
 
-    // Requests that performTraversalsInTransactionFromWindowManager be called at a
+    // Requests that performTraversals be called at a
     // later time to apply changes to surfaces and displays.
     private void scheduleTraversalLocked(boolean inTraversal) {
         if (!mPendingTraversal && mWindowManagerInternal != null) {
@@ -2031,8 +2032,8 @@
         }
 
         @Override
-        public void performTraversalInTransactionFromWindowManager() {
-            performTraversalInTransactionFromWindowManagerInternal();
+        public void performTraversal(SurfaceControl.Transaction t) {
+            performTraversalInternal(t);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 0d8ec6d..5ca9abc 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -584,10 +584,9 @@
         }
 
         @Override
-        public void requestDisplayModesInTransactionLocked(
-                int colorMode, int modeId) {
-            if (requestModeInTransactionLocked(modeId) ||
-                    requestColorModeInTransactionLocked(colorMode)) {
+        public void requestDisplayModesLocked(int colorMode, int modeId) {
+            if (requestModeLocked(modeId) ||
+                    requestColorModeLocked(colorMode)) {
                 updateDeviceInfoLocked();
             }
         }
@@ -597,7 +596,7 @@
             updateDeviceInfoLocked();
         }
 
-        public boolean requestModeInTransactionLocked(int modeId) {
+        public boolean requestModeLocked(int modeId) {
             if (modeId == 0) {
                 modeId = mDefaultModeId;
             } else if (mSupportedModes.indexOfKey(modeId) < 0) {
@@ -623,7 +622,7 @@
             return true;
         }
 
-        public boolean requestColorModeInTransactionLocked(int colorMode) {
+        public boolean requestColorModeLocked(int colorMode) {
             if (mActiveColorMode == colorMode) {
                 return false;
             }
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index e582fdf..23ee56b 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -21,6 +21,7 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -304,17 +305,18 @@
      * @param device The display device to modify.
      * @param isBlanked True if the device is being blanked.
      */
-    public void configureDisplayInTransactionLocked(DisplayDevice device,
+    public void configureDisplayLocked(SurfaceControl.Transaction t,
+            DisplayDevice device,
             boolean isBlanked) {
         // Set the layer stack.
-        device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
+        device.setLayerStackLocked(t, isBlanked ? BLANK_LAYER_STACK : mLayerStack);
 
         // Set the color mode and mode.
         if (device == mPrimaryDisplayDevice) {
-            device.requestDisplayModesInTransactionLocked(
+            device.requestDisplayModesLocked(
                     mRequestedColorMode, mRequestedModeId);
         } else {
-            device.requestDisplayModesInTransactionLocked(0, 0);  // Revert to default.
+            device.requestDisplayModesLocked(0, 0);  // Revert to default.
         }
 
         // Only grab the display info now as it may have been changed based on the requests above.
@@ -377,7 +379,7 @@
         mTempDisplayRect.right += mDisplayOffsetX;
         mTempDisplayRect.top += mDisplayOffsetY;
         mTempDisplayRect.bottom += mDisplayOffsetY;
-        device.setProjectionInTransactionLocked(orientation, mTempLayerStackRect, mTempDisplayRect);
+        device.setProjectionLocked(t, orientation, mTempLayerStackRect, mTempDisplayRect);
     }
 
     /**
diff --git a/services/core/java/com/android/server/display/OWNERS b/services/core/java/com/android/server/display/OWNERS
index 8361421..98e3299 100644
--- a/services/core/java/com/android/server/display/OWNERS
+++ b/services/core/java/com/android/server/display/OWNERS
@@ -1,3 +1,5 @@
 michaelwr@google.com
+hackbod@google.com
+ogunwale@google.com
 
-per-file ColorDisplayService.java=christyfranks@google.com
\ No newline at end of file
+per-file ColorDisplayService.java=christyfranks@google.com
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index 27327d4..e65637f 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -271,12 +271,12 @@
         }
 
         @Override
-        public void performTraversalInTransactionLocked() {
+        public void performTraversalLocked(SurfaceControl.Transaction t) {
             if (mSurfaceTexture != null) {
                 if (mSurface == null) {
                     mSurface = new Surface(mSurfaceTexture);
                 }
-                setSurfaceInTransactionLocked(mSurface);
+                setSurfaceLocked(t, mSurface);
             }
         }
 
@@ -315,7 +315,7 @@
         }
 
         @Override
-        public void requestDisplayModesInTransactionLocked(int color, int id) {
+        public void requestDisplayModesLocked(int color, int id) {
             int index = -1;
             if (id == 0) {
                 // Use the default.
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index f86d576..6111c23 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -269,12 +269,12 @@
         }
 
         @Override
-        public void performTraversalInTransactionLocked() {
+        public void performTraversalLocked(SurfaceControl.Transaction t) {
             if ((mPendingChanges & PENDING_RESIZE) != 0) {
-                SurfaceControl.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
+                t.setDisplaySize(getDisplayTokenLocked(), mWidth, mHeight);
             }
             if ((mPendingChanges & PENDING_SURFACE_CHANGE) != 0) {
-                setSurfaceInTransactionLocked(mSurface);
+                setSurfaceLocked(t, mSurface);
             }
             mPendingChanges = 0;
         }
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 3293379..e8d6ad4 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -620,9 +620,9 @@
         }
 
         @Override
-        public void performTraversalInTransactionLocked() {
+        public void performTraversalLocked(SurfaceControl.Transaction t) {
             if (mSurface != null) {
-                setSurfaceInTransactionLocked(mSurface);
+                setSurfaceLocked(t, mSurface);
             }
         }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
index 1bd5f42..5bfdf41 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java
@@ -45,6 +45,7 @@
 import java.security.SecureRandom;
 import java.security.UnrecoverableKeyException;
 import java.security.cert.CertPath;
+import java.security.cert.CertificateException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -295,17 +296,23 @@
         // If application keys are not updated, snapshot will not be created on next unlock.
         mRecoverableKeyStoreDb.setShouldCreateSnapshot(mUserId, recoveryAgentUid, false);
 
-        mRecoverySnapshotStorage.put(recoveryAgentUid, new KeyChainSnapshot.Builder()
+        KeyChainSnapshot.Builder keyChainSnapshotBuilder = new KeyChainSnapshot.Builder()
                 .setSnapshotVersion(getSnapshotVersion(recoveryAgentUid, recreateCurrentVersion))
                 .setMaxAttempts(TRUSTED_HARDWARE_MAX_ATTEMPTS)
                 .setCounterId(counterId)
                 .setTrustedHardwarePublicKey(SecureBox.encodePublicKey(publicKey))
-                .setTrustedHardwareCertPath(certPath)
                 .setServerParams(vaultHandle)
                 .setKeyChainProtectionParams(metadataList)
                 .setWrappedApplicationKeys(createApplicationKeyEntries(encryptedApplicationKeys))
-                .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey)
-                .build());
+                .setEncryptedRecoveryKeyBlob(encryptedRecoveryKey);
+        try {
+            keyChainSnapshotBuilder.setTrustedHardwareCertPath(certPath);
+        } catch(CertificateException e) {
+            // Should not happen, as it's just deserialized from bytes stored in the db
+            Log.wtf(TAG, "Cannot serialize CertPath when calling setTrustedHardwareCertPath", e);
+            return;
+        }
+        mRecoverySnapshotStorage.put(recoveryAgentUid, keyChainSnapshotBuilder.build());
 
         mSnapshotListenersStorage.recoverySnapshotAvailable(recoveryAgentUid);
     }
diff --git a/services/core/java/com/android/server/media/OWNERS b/services/core/java/com/android/server/media/OWNERS
index 755c1d6..8adea0e 100644
--- a/services/core/java/com/android/server/media/OWNERS
+++ b/services/core/java/com/android/server/media/OWNERS
@@ -1,3 +1,4 @@
 lajos@google.com
 elaurent@google.com
 sungsoo@google.com
+jaewan@google.com
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ab55553..efca159 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2852,6 +2852,32 @@
                                 ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
                         .build());
 
+            } else if ("month_over".equals(fake)) {
+                plans.add(SubscriptionPlan.Builder
+                        .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
+                        .setTitle("G-Mobile is the carriers name who this plan belongs to")
+                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                                SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
+                        .setDataUsage(6 * TrafficStats.GB_IN_BYTES,
+                                ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
+                        .build());
+                plans.add(SubscriptionPlan.Builder
+                        .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z"))
+                        .setTitle("G-Mobile, Throttled after limit")
+                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                                SubscriptionPlan.LIMIT_BEHAVIOR_THROTTLED)
+                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                                ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
+                        .build());
+                plans.add(SubscriptionPlan.Builder
+                        .createRecurringMonthly(ZonedDateTime.parse("2017-03-14T00:00:00.000Z"))
+                        .setTitle("G-Mobile, No data connection after limit")
+                        .setDataLimit(5 * TrafficStats.GB_IN_BYTES,
+                                SubscriptionPlan.LIMIT_BEHAVIOR_DISABLED)
+                        .setDataUsage(5 * TrafficStats.GB_IN_BYTES,
+                                ZonedDateTime.now().minusHours(1).toInstant().toEpochMilli())
+                        .build());
+
             } else if ("month_none".equals(fake)) {
                 plans.add(SubscriptionPlan.Builder
                         .createRecurringMonthly(ZonedDateTime.parse("2007-03-14T00:00:00.000Z"))
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1082478..f4360e4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -176,6 +176,7 @@
 import android.content.pm.PackageParser.PackageParserException;
 import android.content.pm.PackageParser.ParseFlags;
 import android.content.pm.PackageParser.ServiceIntentInfo;
+import android.content.pm.PackageParser.SigningDetails;
 import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
 import android.content.pm.PackageStats;
 import android.content.pm.PackageUserState;
@@ -4086,14 +4087,24 @@
             @Nullable ComponentName component, @ComponentType int type) {
         if (type == TYPE_ACTIVITY) {
             final PackageParser.Activity activity = mActivities.mActivities.get(component);
-            return activity != null
-                    ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
-                    : false;
+            if (activity == null) {
+                return false;
+            }
+            final boolean visibleToInstantApp =
+                    (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+            final boolean explicitlyVisibleToInstantApp =
+                    (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+            return visibleToInstantApp && explicitlyVisibleToInstantApp;
         } else if (type == TYPE_RECEIVER) {
             final PackageParser.Activity activity = mReceivers.mActivities.get(component);
-            return activity != null
-                    ? (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0
-                    : false;
+            if (activity == null) {
+                return false;
+            }
+            final boolean visibleToInstantApp =
+                    (activity.info.flags & ActivityInfo.FLAG_VISIBLE_TO_INSTANT_APP) != 0;
+            final boolean explicitlyVisibleToInstantApp =
+                    (activity.info.flags & ActivityInfo.FLAG_IMPLICITLY_VISIBLE_TO_INSTANT_APP) == 0;
+            return visibleToInstantApp && !explicitlyVisibleToInstantApp;
         } else if (type == TYPE_SERVICE) {
             final PackageParser.Service service = mServices.mServices.get(component);
             return service != null
@@ -4138,6 +4149,10 @@
             return false;
         }
         if (callerIsInstantApp) {
+            // both caller and target are both instant, but, different applications, filter
+            if (ps.getInstantApp(userId)) {
+                return true;
+            }
             // request for a specific component; if it hasn't been explicitly exposed through
             // property or instrumentation target, filter
             if (component != null) {
@@ -4150,7 +4165,7 @@
                 return !isComponentVisibleToInstantApp(component, componentType);
             }
             // request for application; if no components have been explicitly exposed, filter
-            return ps.getInstantApp(userId) || !ps.pkg.visibleToInstantApps;
+            return !ps.pkg.visibleToInstantApps;
         }
         if (ps.getInstantApp(userId)) {
             // caller can see all components of all instant applications, don't filter
@@ -23383,6 +23398,36 @@
         }
 
         @Override
+        public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) {
+            SigningDetails sd = getSigningDetails(packageName);
+            if (sd == null) {
+                return false;
+            }
+            return sd.hasSha256Certificate(restoringFromSigHash,
+                    SigningDetails.CertCapabilities.INSTALLED_DATA);
+        }
+
+        @Override
+        public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) {
+            SigningDetails sd = getSigningDetails(packageName);
+            if (sd == null) {
+                return false;
+            }
+            return sd.hasCertificate(restoringFromSig,
+                    SigningDetails.CertCapabilities.INSTALLED_DATA);
+        }
+
+        private SigningDetails getSigningDetails(@NonNull String packageName) {
+            synchronized (mPackages) {
+                PackageParser.Package p = mPackages.get(packageName);
+                if (p == null) {
+                    return null;
+                }
+                return p.mSigningDetails;
+            }
+        }
+
+        @Override
         public int getPermissionFlagsTEMP(String permName, String packageName, int userId) {
             return PackageManagerService.this.getPermissionFlags(permName, packageName, userId);
         }
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 520ed25..eeaa333 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -18,10 +18,13 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.ShortcutInfo;
+import android.content.pm.Signature;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.LocalServices;
 import com.android.server.backup.BackupUtils;
 
 import libcore.util.HexEncoding;
@@ -137,7 +140,8 @@
 
     //@DisabledReason
     public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) {
-        if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) {
+        PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+        if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage, pmi)) {
             Slog.w(TAG, "Can't restore: Package signature mismatch");
             return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
         }
@@ -159,13 +163,15 @@
     public static ShortcutPackageInfo generateForInstalledPackageForTest(
             ShortcutService s, String packageName, @UserIdInt int packageUserId) {
         final PackageInfo pi = s.getPackageInfoWithSignatures(packageName, packageUserId);
-        if (pi.signatures == null || pi.signatures.length == 0) {
+        // retrieve the newest sigs
+        Signature[][] signingHistory = pi.signingCertificateHistory;
+        if (signingHistory == null || signingHistory.length == 0) {
             Slog.e(TAG, "Can't get signatures: package=" + packageName);
             return null;
         }
+        Signature[] signatures = signingHistory[signingHistory.length - 1];
         final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.getLongVersionCode(),
-                pi.lastUpdateTime, BackupUtils.hashSignatureArray(pi.signatures),
-                /* shadow=*/ false);
+                pi.lastUpdateTime, BackupUtils.hashSignatureArray(signatures), /* shadow=*/ false);
 
         ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi);
         ret.mBackupSourceVersionCode = pi.getLongVersionCode();
@@ -185,7 +191,15 @@
             Slog.w(TAG, "Package not found: " + pkg.getPackageName());
             return;
         }
-        mSigHashes = BackupUtils.hashSignatureArray(pi.signatures);
+        // retrieve the newest sigs
+        Signature[][] signingHistory = pi.signingCertificateHistory;
+        if (signingHistory == null || signingHistory.length == 0) {
+            Slog.w(TAG, "Not refreshing signature for " + pkg.getPackageName()
+                    + " since it appears to have no signature history.");
+            return;
+        }
+        Signature[] signatures = signingHistory[signingHistory.length - 1];
+        mSigHashes = BackupUtils.hashSignatureArray(signatures);
     }
 
     public void saveToXml(ShortcutService s, XmlSerializer out, boolean forBackup)
@@ -221,7 +235,6 @@
 
     public void loadFromXml(XmlPullParser parser, boolean fromBackup)
             throws IOException, XmlPullParserException {
-
         // Don't use the version code from the backup file.
         final long versionCode = ShortcutService.parseLongAttribute(parser, ATTR_VERSION,
                 ShortcutInfo.VERSION_CODE_UNKNOWN);
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 265cc8e..15b4617 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -3121,7 +3121,8 @@
         try {
             return mIPackageManager.getPackageInfo(
                     packageName, PACKAGE_MATCH_FLAGS
-                            | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId);
+                            | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0),
+                    userId);
         } catch (RemoteException e) {
             // Shouldn't happen.
             Slog.wtf(TAG, "RemoteException", e);
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 954627b..afcedcc 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -720,11 +720,13 @@
         long elapsedNanos = SystemClock.elapsedRealtimeNanos();
         mKernelUidCpuFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> {
             for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) {
-                StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
-                e.writeInt(uid);
-                e.writeInt(freqIndex);
-                e.writeLong(cpuFreqTimeMs[freqIndex]);
-                pulledData.add(e);
+                if(cpuFreqTimeMs[freqIndex] != 0) {
+                    StatsLogEventWrapper e = new StatsLogEventWrapper(elapsedNanos, tagId, 3);
+                    e.writeInt(uid);
+                    e.writeInt(freqIndex);
+                    e.writeLong(cpuFreqTimeMs[freqIndex]);
+                    pulledData.add(e);
+                }
             }
         });
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b2f153a..fef615d 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1092,7 +1092,7 @@
                 mService.registerAppFreezeListener(this);
                 mService.mAppsFreezingScreen++;
                 if (mService.mAppsFreezingScreen == 1) {
-                    mService.startFreezingDisplayLocked(false, 0, 0, getDisplayContent());
+                    mService.startFreezingDisplayLocked(0, 0, getDisplayContent());
                     mService.mH.removeMessages(H.APP_FREEZE_TIMEOUT);
                     mService.mH.sendEmptyMessageDelayed(H.APP_FREEZE_TIMEOUT, 2000);
                 }
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index f19cd0f..1977e12 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -41,7 +41,7 @@
         final int layer;
         final SurfaceControl surface;
 
-        BlackSurface(int layer,
+        BlackSurface(SurfaceControl.Transaction transaction, int layer,
                 int l, int t, int r, int b, DisplayContent dc) throws OutOfResourcesException {
             left = l;
             top = t;
@@ -56,24 +56,24 @@
                     .setParent(null) // TODO: Work-around for b/69259549
                     .build();
 
-            surface.setAlpha(1);
-            surface.setLayer(layer);
-            surface.show();
+            transaction.setAlpha(surface, 1);
+            transaction.setLayer(surface, layer);
+            transaction.show(surface);
             if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
                             "  BLACK " + surface + ": CREATE layer=" + layer);
         }
 
-        void setAlpha(float alpha) {
-            surface.setAlpha(alpha);
+        void setAlpha(SurfaceControl.Transaction t, float alpha) {
+            t.setAlpha(surface, alpha);
         }
 
-        void setMatrix(Matrix matrix) {
+        void setMatrix(SurfaceControl.Transaction t, Matrix matrix) {
             mTmpMatrix.setTranslate(left, top);
             mTmpMatrix.postConcat(matrix);
             mTmpMatrix.getValues(mTmpFloats);
-            surface.setPosition(mTmpFloats[Matrix.MTRANS_X],
+            t.setPosition(surface, mTmpFloats[Matrix.MTRANS_X],
                     mTmpFloats[Matrix.MTRANS_Y]);
-            surface.setMatrix(
+            t.setMatrix(surface,
                     mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                     mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
             if (false) {
@@ -87,8 +87,8 @@
             }
         }
 
-        void clearMatrix() {
-            surface.setMatrix(1, 0, 0, 1);
+        void clearMatrix(SurfaceControl.Transaction t) {
+            t.setMatrix(surface, 1, 0, 0, 1);
         }
     }
 
@@ -113,7 +113,8 @@
         }
     }
 
-    public BlackFrame(Rect outer, Rect inner, int layer, DisplayContent dc,
+    public BlackFrame(SurfaceControl.Transaction t,
+            Rect outer, Rect inner, int layer, DisplayContent dc,
             boolean forceDefaultOrientation) throws OutOfResourcesException {
         boolean success = false;
 
@@ -125,19 +126,19 @@
         mInnerRect = new Rect(inner);
         try {
             if (outer.top < inner.top) {
-                mBlackSurfaces[0] = new BlackSurface(layer,
+                mBlackSurfaces[0] = new BlackSurface(t, layer,
                         outer.left, outer.top, inner.right, inner.top, dc);
             }
             if (outer.left < inner.left) {
-                mBlackSurfaces[1] = new BlackSurface(layer,
+                mBlackSurfaces[1] = new BlackSurface(t, layer,
                         outer.left, inner.top, inner.left, outer.bottom, dc);
             }
             if (outer.bottom > inner.bottom) {
-                mBlackSurfaces[2] = new BlackSurface(layer,
+                mBlackSurfaces[2] = new BlackSurface(t, layer,
                         inner.left, inner.bottom, outer.right, outer.bottom, dc);
             }
             if (outer.right > inner.right) {
-                mBlackSurfaces[3] = new BlackSurface(layer,
+                mBlackSurfaces[3] = new BlackSurface(t, layer,
                         inner.right, outer.top, outer.right, inner.bottom, dc);
             }
             success = true;
@@ -161,36 +162,36 @@
         }
     }
 
-    public void hide() {
+    public void hide(SurfaceControl.Transaction t) {
         if (mBlackSurfaces != null) {
             for (int i=0; i<mBlackSurfaces.length; i++) {
                 if (mBlackSurfaces[i] != null) {
-                    mBlackSurfaces[i].surface.hide();
+                    t.hide(mBlackSurfaces[i].surface);
                 }
             }
         }
     }
 
-    public void setAlpha(float alpha) {
+    public void setAlpha(SurfaceControl.Transaction t, float alpha) {
         for (int i=0; i<mBlackSurfaces.length; i++) {
             if (mBlackSurfaces[i] != null) {
-                mBlackSurfaces[i].setAlpha(alpha);
+                mBlackSurfaces[i].setAlpha(t, alpha);
             }
         }
     }
 
-    public void setMatrix(Matrix matrix) {
+    public void setMatrix(SurfaceControl.Transaction t, Matrix matrix) {
         for (int i=0; i<mBlackSurfaces.length; i++) {
             if (mBlackSurfaces[i] != null) {
-                mBlackSurfaces[i].setMatrix(matrix);
+                mBlackSurfaces[i].setMatrix(t, matrix);
             }
         }
     }
 
-    public void clearMatrix() {
+    public void clearMatrix(SurfaceControl.Transaction t) {
         for (int i=0; i<mBlackSurfaces.length; i++) {
             if (mBlackSurfaces[i] != null) {
-                mBlackSurfaces[i].clearMatrix();
+                mBlackSurfaces[i].clearMatrix(t);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 2dce913..59babcf 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -258,7 +258,7 @@
      * Current rotation of the display.
      * Constants as per {@link android.view.Surface.Rotation}.
      *
-     * @see #updateRotationUnchecked(boolean)
+     * @see #updateRotationUnchecked()
      */
     private int mRotation = 0;
 
@@ -274,7 +274,7 @@
      * Flag indicating that the application is receiving an orientation that has different metrics
      * than it expected. E.g. Portrait instead of Landscape.
      *
-     * @see #updateRotationUnchecked(boolean)
+     * @see #updateRotationUnchecked()
      */
     private boolean mAltOrientation = false;
 
@@ -926,7 +926,7 @@
      * Returns true if the rotation has been changed.  In this case YOU MUST CALL
      * {@link WindowManagerService#sendNewConfiguration(int)} TO UNFREEZE THE SCREEN.
      */
-    boolean updateRotationUnchecked(boolean inTransaction) {
+    boolean updateRotationUnchecked() {
         if (mService.mDeferredRotationPauseCount > 0) {
             // Rotation updates have been paused temporarily.  Defer the update until
             // updates have been resumed.
@@ -1030,7 +1030,7 @@
         mService.mPolicy.selectRotationAnimationLw(anim);
 
         if (!rotateSeamlessly) {
-            mService.startFreezingDisplayLocked(inTransaction, anim[0], anim[1], this);
+            mService.startFreezingDisplayLocked(anim[0], anim[1], this);
             // startFreezingDisplayLocked can reset the ScreenRotationAnimation.
             screenRotationAnimation = mService.mAnimator.getScreenRotationAnimationLocked(
                     mDisplayId);
@@ -1041,9 +1041,7 @@
             // to their rotated state independently and without a freeze required.
             screenRotationAnimation = null;
 
-            // We have to reset this in case a window was removed before it
-            // finished seamless rotation.
-            mService.mSeamlessRotationCount = 0;
+            mService.startSeamlessRotation();
         }
 
         // We need to update our screen size information to match the new rotation. If the rotation
@@ -1053,40 +1051,27 @@
         // #computeScreenConfiguration() later.
         updateDisplayAndOrientation(getConfiguration().uiMode);
 
-        if (!inTransaction) {
-            if (SHOW_TRANSACTIONS) {
-                Slog.i(TAG_WM, ">>> OPEN TRANSACTION setRotationUnchecked");
-            }
-            mService.openSurfaceTransaction();
-        }
-        try {
-            // NOTE: We disable the rotation in the emulator because
-            //       it doesn't support hardware OpenGL emulation yet.
-            if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
-                    && screenRotationAnimation.hasScreenshot()) {
-                if (screenRotationAnimation.setRotationInTransaction(rotation,
-                        MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(),
-                        mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
-                    mService.scheduleAnimationLocked();
-                }
-            }
-
-            if (rotateSeamlessly) {
-                forAllWindows(w -> {
-                    w.mWinAnimator.seamlesslyRotateWindow(oldRotation, rotation);
-                }, true /* traverseTopToBottom */);
-            }
-
-            mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
-        } finally {
-            if (!inTransaction) {
-                mService.closeSurfaceTransaction("setRotationUnchecked");
-                if (SHOW_LIGHT_TRANSACTIONS) {
-                    Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
-                }
+        // NOTE: We disable the rotation in the emulator because
+        //       it doesn't support hardware OpenGL emulation yet.
+        if (CUSTOM_SCREEN_ROTATION && screenRotationAnimation != null
+                && screenRotationAnimation.hasScreenshot()) {
+            if (screenRotationAnimation.setRotation(getPendingTransaction(), rotation,
+                    MAX_ANIMATION_DURATION, mService.getTransitionAnimationScaleLocked(),
+                    mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight)) {
+                mService.scheduleAnimationLocked();
             }
         }
 
+        if (rotateSeamlessly) {
+            forAllWindows(w -> {
+                    w.mWinAnimator.seamlesslyRotateWindow(getPendingTransaction(),
+                            oldRotation, rotation);
+            }, true /* traverseTopToBottom */);
+        }
+
+        mService.mDisplayManagerInternal.performTraversal(getPendingTransaction());
+        scheduleAnimation();
+
         forAllWindows(w -> {
             if (w.mHasSurface && !rotateSeamlessly) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
@@ -2808,7 +2793,7 @@
 
             if (isDefaultDisplay && (pendingLayoutChanges & FINISH_LAYOUT_REDO_CONFIG) != 0) {
                 if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                if (mService.updateOrientationFromAppTokensLocked(true, mDisplayId)) {
+                if (mService.updateOrientationFromAppTokensLocked(mDisplayId)) {
                     setLayoutNeeded();
                     mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mDisplayId).sendToTarget();
                 }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f32c275..32ae523 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -37,6 +37,7 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.DisplayInfo;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 
 import com.android.internal.util.ArrayUtils;
@@ -128,6 +129,11 @@
     private final Handler mHandler;
 
     private String mCloseSystemDialogsReason;
+
+    // Only a seperate transaction until we seperate the apply surface changes
+    // transaction from the global transaction.
+    private final SurfaceControl.Transaction mDisplayTransaction = new SurfaceControl.Transaction();
+
     private final Consumer<WindowState> mCloseSystemDialogsConsumer = w -> {
         if (w.mHasSurface) {
             try {
@@ -725,7 +731,7 @@
             if (DEBUG_ORIENTATION) Slog.d(TAG, "Performing post-rotate rotation");
             // TODO(multi-display): Update rotation for different displays separately.
             final int displayId = defaultDisplay.getDisplayId();
-            if (defaultDisplay.updateRotationUnchecked(false /* inTransaction */)) {
+            if (defaultDisplay.updateRotationUnchecked()) {
                 mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
             } else {
                 mUpdateRotation = false;
@@ -735,7 +741,7 @@
             // PhoneWindowManager.
             final DisplayContent vrDisplay = mService.mVr2dDisplayId != INVALID_DISPLAY
                     ? getDisplayContent(mService.mVr2dDisplayId) : null;
-            if (vrDisplay != null && vrDisplay.updateRotationUnchecked(false /* inTransaction */)) {
+            if (vrDisplay != null && vrDisplay.updateRotationUnchecked()) {
                 mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, mService.mVr2dDisplayId)
                         .sendToTarget();
             }
@@ -835,7 +841,8 @@
 
         // Give the display manager a chance to adjust properties like display rotation if it needs
         // to.
-        mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
+        mService.mDisplayManagerInternal.performTraversal(mDisplayTransaction);
+        SurfaceControl.mergeToGlobalTransaction(mDisplayTransaction);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 5a39de5..ad2fabb 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -224,8 +224,7 @@
     }
 
     public ScreenRotationAnimation(Context context, DisplayContent displayContent,
-            boolean inTransaction, boolean forceDefaultOrientation,
-            boolean isSecure, WindowManagerService service) {
+            boolean forceDefaultOrientation, boolean isSecure, WindowManagerService service) {
         mService = service;
         mContext = context;
         mDisplayContent = displayContent;
@@ -260,52 +259,39 @@
         mOriginalWidth = originalWidth;
         mOriginalHeight = originalHeight;
 
-        if (!inTransaction) {
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
-                    ">>> OPEN TRANSACTION ScreenRotationAnimation");
-            mService.openSurfaceTransaction();
-        }
-
+        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
         try {
-            try {
-                mSurfaceControl = displayContent.makeOverlay()
-                        .setName("ScreenshotSurface")
-                        .setSize(mWidth, mHeight)
-                        .setSecure(isSecure)
-                        .build();
+            mSurfaceControl = displayContent.makeOverlay()
+                    .setName("ScreenshotSurface")
+                    .setSize(mWidth, mHeight)
+                    .setSecure(isSecure)
+                    .build();
 
-                // capture a screenshot into the surface we just created
-                Surface sur = new Surface();
-                sur.copyFrom(mSurfaceControl);
-                // TODO(multidisplay): we should use the proper display
-                SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
-                        SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
-                mSurfaceControl.setLayer(SCREEN_FREEZE_LAYER_SCREENSHOT);
-                mSurfaceControl.setAlpha(0);
-                mSurfaceControl.show();
-                sur.destroy();
-            } catch (OutOfResourcesException e) {
-                Slog.w(TAG, "Unable to allocate freeze surface", e);
-            }
-
-            if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
-                    "  FREEZE " + mSurfaceControl + ": CREATE");
-
-            setRotationInTransaction(originalRotation);
-        } finally {
-            if (!inTransaction) {
-                mService.closeSurfaceTransaction("ScreenRotationAnimation");
-                if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
-                        "<<< CLOSE TRANSACTION ScreenRotationAnimation");
-            }
+            // capture a screenshot into the surface we just created
+            Surface sur = new Surface();
+            sur.copyFrom(mSurfaceControl);
+            // TODO(multidisplay): we should use the proper display
+            SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
+                            SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), sur);
+            t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
+            t.setAlpha(mSurfaceControl, 0);
+            t.show(mSurfaceControl);
+            sur.destroy();
+        } catch (OutOfResourcesException e) {
+            Slog.w(TAG, "Unable to allocate freeze surface", e);
         }
+
+        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
+                "  FREEZE " + mSurfaceControl + ": CREATE");
+        setRotation(t, originalRotation);
+        t.apply();
     }
 
     boolean hasScreenshot() {
         return mSurfaceControl != null;
     }
 
-    private void setSnapshotTransformInTransaction(Matrix matrix, float alpha) {
+    private void setSnapshotTransform(SurfaceControl.Transaction t, Matrix matrix, float alpha) {
         if (mSurfaceControl != null) {
             matrix.getValues(mTmpFloats);
             float x = mTmpFloats[Matrix.MTRANS_X];
@@ -315,11 +301,11 @@
                 x -= mCurrentDisplayRect.left;
                 y -= mCurrentDisplayRect.top;
             }
-            mSurfaceControl.setPosition(x, y);
-            mSurfaceControl.setMatrix(
+            t.setPosition(mSurfaceControl, x, y);
+            t.setMatrix(mSurfaceControl,
                     mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y],
                     mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]);
-            mSurfaceControl.setAlpha(alpha);
+            t.setAlpha(mSurfaceControl, alpha);
             if (DEBUG_TRANSFORMS) {
                 float[] srcPnts = new float[] { 0, 0, mWidth, mHeight };
                 float[] dstPnts = new float[4];
@@ -353,8 +339,7 @@
         }
     }
 
-    // Must be called while in a transaction.
-    private void setRotationInTransaction(int rotation) {
+    private void setRotation(SurfaceControl.Transaction t, int rotation) {
         mCurRotation = rotation;
 
         // Compute the transformation matrix that must be applied
@@ -364,15 +349,14 @@
         createRotationMatrix(delta, mWidth, mHeight, mSnapshotInitialMatrix);
 
         if (DEBUG_STATE) Slog.v(TAG, "**** ROTATION: " + delta);
-        setSnapshotTransformInTransaction(mSnapshotInitialMatrix, 1.0f);
+        setSnapshotTransform(t, mSnapshotInitialMatrix, 1.0f);
     }
 
-    // Must be called while in a transaction.
-    public boolean setRotationInTransaction(int rotation,
+    public boolean setRotation(SurfaceControl.Transaction t, int rotation,
             long maxAnimationDuration, float animationScale, int finalWidth, int finalHeight) {
-        setRotationInTransaction(rotation);
+        setRotation(t, rotation);
         if (TWO_PHASE_ANIMATION) {
-            return startAnimation(maxAnimationDuration, animationScale,
+            return startAnimation(t, maxAnimationDuration, animationScale,
                     finalWidth, finalHeight, false, 0, 0);
         }
 
@@ -383,7 +367,7 @@
     /**
      * Returns true if animating.
      */
-    private boolean startAnimation(long maxAnimationDuration,
+    private boolean startAnimation(SurfaceControl.Transaction t, long maxAnimationDuration,
             float animationScale, int finalWidth, int finalHeight, boolean dismissing,
             int exitAnim, int enterAnim) {
         if (mSurfaceControl == null) {
@@ -542,11 +526,6 @@
 
         final int layerStack = mDisplayContent.getDisplay().getLayerStack();
         if (USE_CUSTOM_BLACK_FRAME && mCustomBlackFrame == null) {
-            if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
-                    TAG_WM,
-                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            mService.openSurfaceTransaction();
-
             // Compute the transformation matrix that must be applied
             // the the black frame to make it stay in the initial position
             // before the new screen rotation.  This is different than the
@@ -559,24 +538,15 @@
                 Rect outer = new Rect(-mOriginalWidth*1, -mOriginalHeight*1,
                         mOriginalWidth*2, mOriginalHeight*2);
                 Rect inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
-                mCustomBlackFrame = new BlackFrame(outer, inner,
+                mCustomBlackFrame = new BlackFrame(t, outer, inner,
                         SCREEN_FREEZE_LAYER_CUSTOM, mDisplayContent, false);
-                mCustomBlackFrame.setMatrix(mFrameInitialMatrix);
+                mCustomBlackFrame.setMatrix(t, mFrameInitialMatrix);
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
-            } finally {
-                mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
-                if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
-                        TAG_WM,
-                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
             }
         }
 
         if (!customAnim && mExitingBlackFrame == null) {
-            if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
-                    TAG_WM,
-                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            mService.openSurfaceTransaction();
             try {
                 // Compute the transformation matrix that must be applied
                 // the the black frame to make it stay in the initial position
@@ -599,38 +569,23 @@
                             mOriginalWidth*2, mOriginalHeight*2);
                     inner = new Rect(0, 0, mOriginalWidth, mOriginalHeight);
                 }
-                mExitingBlackFrame = new BlackFrame(outer, inner,
+                mExitingBlackFrame = new BlackFrame(t, outer, inner,
                         SCREEN_FREEZE_LAYER_EXIT, mDisplayContent, mForceDefaultOrientation);
-                mExitingBlackFrame.setMatrix(mFrameInitialMatrix);
+                mExitingBlackFrame.setMatrix(t, mFrameInitialMatrix);
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
-            } finally {
-                mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
-                if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
-                        TAG_WM,
-                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
             }
         }
 
         if (customAnim && mEnteringBlackFrame == null) {
-            if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
-                    TAG_WM,
-                    ">>> OPEN TRANSACTION ScreenRotationAnimation.startAnimation");
-            mService.openSurfaceTransaction();
-
             try {
                 Rect outer = new Rect(-finalWidth*1, -finalHeight*1,
                         finalWidth*2, finalHeight*2);
                 Rect inner = new Rect(0, 0, finalWidth, finalHeight);
-                mEnteringBlackFrame = new BlackFrame(outer, inner,
+                mEnteringBlackFrame = new BlackFrame(t, outer, inner,
                         SCREEN_FREEZE_LAYER_ENTER, mDisplayContent, false);
             } catch (OutOfResourcesException e) {
                 Slog.w(TAG, "Unable to allocate black surface", e);
-            } finally {
-                mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
-                if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
-                        TAG_WM,
-                        "<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
             }
         }
 
@@ -640,7 +595,7 @@
     /**
      * Returns true if animating.
      */
-    public boolean dismiss(long maxAnimationDuration,
+    public boolean dismiss(SurfaceControl.Transaction t, long maxAnimationDuration,
             float animationScale, int finalWidth, int finalHeight, int exitAnim, int enterAnim) {
         if (DEBUG_STATE) Slog.v(TAG, "Dismiss!");
         if (mSurfaceControl == null) {
@@ -648,7 +603,7 @@
             return false;
         }
         if (!mStarted) {
-            startAnimation(maxAnimationDuration, animationScale, finalWidth, finalHeight,
+            startAnimation(t, maxAnimationDuration, animationScale, finalWidth, finalHeight,
                     true, exitAnim, enterAnim);
         }
         if (!mStarted) {
@@ -919,7 +874,7 @@
         return more;
     }
 
-    void updateSurfacesInTransaction() {
+    void updateSurfaces(SurfaceControl.Transaction t) {
         if (!mStarted) {
             return;
         }
@@ -927,28 +882,28 @@
         if (mSurfaceControl != null) {
             if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
                 if (DEBUG_STATE) Slog.v(TAG, "Exit animations done, hiding screenshot surface");
-                mSurfaceControl.hide();
+                t.hide(mSurfaceControl);
             }
         }
 
         if (mCustomBlackFrame != null) {
             if (!mMoreStartFrame && !mMoreFinishFrame && !mMoreRotateFrame) {
                 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding black frame");
-                mCustomBlackFrame.hide();
+                mCustomBlackFrame.hide(t);
             } else {
-                mCustomBlackFrame.setMatrix(mFrameTransformation.getMatrix());
+                mCustomBlackFrame.setMatrix(t, mFrameTransformation.getMatrix());
             }
         }
 
         if (mExitingBlackFrame != null) {
             if (!mMoreStartExit && !mMoreFinishExit && !mMoreRotateExit) {
                 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding exiting frame");
-                mExitingBlackFrame.hide();
+                mExitingBlackFrame.hide(t);
             } else {
                 mExitFrameFinalMatrix.setConcat(mExitTransformation.getMatrix(), mFrameInitialMatrix);
-                mExitingBlackFrame.setMatrix(mExitFrameFinalMatrix);
+                mExitingBlackFrame.setMatrix(t, mExitFrameFinalMatrix);
                 if (mForceDefaultOrientation) {
-                    mExitingBlackFrame.setAlpha(mExitTransformation.getAlpha());
+                    mExitingBlackFrame.setAlpha(t, mExitTransformation.getAlpha());
                 }
             }
         }
@@ -956,13 +911,13 @@
         if (mEnteringBlackFrame != null) {
             if (!mMoreStartEnter && !mMoreFinishEnter && !mMoreRotateEnter) {
                 if (DEBUG_STATE) Slog.v(TAG, "Frame animations done, hiding entering frame");
-                mEnteringBlackFrame.hide();
+                mEnteringBlackFrame.hide(t);
             } else {
-                mEnteringBlackFrame.setMatrix(mEnterTransformation.getMatrix());
+                mEnteringBlackFrame.setMatrix(t, mEnterTransformation.getMatrix());
             }
         }
 
-        setSnapshotTransformInTransaction(mSnapshotFinalMatrix, mExitTransformation.getAlpha());
+        setSnapshotTransform(t, mSnapshotFinalMatrix, mExitTransformation.getAlpha());
     }
 
     public boolean stepAnimationLocked(long now) {
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index ab10197..793ffce 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -30,6 +30,7 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.view.Choreographer;
+import android.view.SurfaceControl;
 
 import com.android.server.AnimationThread;
 import com.android.server.policy.WindowManagerPolicy;
@@ -94,6 +95,8 @@
     private final ArrayList<Runnable> mAfterPrepareSurfacesRunnables = new ArrayList<>();
     private boolean mInExecuteAfterPrepareSurfacesRunnables;
 
+    private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction();
+
     WindowAnimator(final WindowManagerService service) {
         mService = service;
         mContext = service.mContext;
@@ -203,7 +206,7 @@
                     final ScreenRotationAnimation screenRotationAnimation =
                             mDisplayContentsAnimators.valueAt(i).mScreenRotationAnimation;
                     if (screenRotationAnimation != null) {
-                        screenRotationAnimation.updateSurfacesInTransaction();
+                        screenRotationAnimation.updateSurfaces(mTransaction);
                     }
                     orAnimating(dc.getDockedDividerController().animate(mCurrentTime));
                     //TODO (multidisplay): Magnification is supported only for the default display.
@@ -219,6 +222,8 @@
                 if (mService.mWatermark != null) {
                     mService.mWatermark.drawIfNeeded();
                 }
+
+                SurfaceControl.mergeToGlobalTransaction(mTransaction);
             } catch (RuntimeException e) {
                 Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
             } finally {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 82fbb51..be009d2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -667,11 +667,18 @@
     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
     SettingsObserver mSettingsObserver;
 
-    // A count of the windows which are 'seamlessly rotated', e.g. a surface
-    // at an old orientation is being transformed. We freeze orientation updates
-    // while any windows are seamlessly rotated, so we need to track when this
-    // hits zero so we can apply deferred orientation updates.
-    int mSeamlessRotationCount = 0;
+    /**
+     * A count of the windows which are 'seamlessly rotated', e.g. a surface
+     * at an old orientation is being transformed. We freeze orientation updates
+     * while any windows are seamlessly rotated, so we need to track when this
+     * hits zero so we can apply deferred orientation updates.
+     */
+    private int mSeamlessRotationCount = 0;
+    /**
+     * True in the interval from starting seamless rotation until the last rotated
+     * window draws in the new orientation.
+     */
+    private boolean mRotatingSeamlessly = false;
 
     private final class SettingsObserver extends ContentObserver {
         private final Uri mDisplayInversionEnabledUri =
@@ -809,6 +816,8 @@
     SurfaceBuilderFactory mSurfaceBuilderFactory = SurfaceControl.Builder::new;
     TransactionFactory mTransactionFactory = SurfaceControl.Transaction::new;
 
+    private final SurfaceControl.Transaction mTransaction = mTransactionFactory.make();
+
     static void boostPriorityForLockedSection() {
         sThreadPriorityBooster.boost();
     }
@@ -1487,7 +1496,7 @@
             if (localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addWindow: New client "
                     + client.asBinder() + ": window=" + win + " Callers=" + Debug.getCallers(5));
 
-            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false, displayId)) {
+            if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(displayId)) {
                 reportNewConfig = true;
             }
         }
@@ -2049,7 +2058,7 @@
 
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                     "relayoutWindow: updateOrientationFromAppTokens");
-            configChanged = updateOrientationFromAppTokensLocked(false, displayId);
+            configChanged = updateOrientationFromAppTokensLocked(displayId);
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
 
             if (toBeDisplayed && win.mIsWallpaper) {
@@ -2340,7 +2349,7 @@
         }
         Configuration config = null;
 
-        if (updateOrientationFromAppTokensLocked(false, displayId)) {
+        if (updateOrientationFromAppTokensLocked(displayId)) {
             // If we changed the orientation but mOrientationChangeComplete is already true,
             // we used seamless rotation, and we don't need to freeze the screen.
             if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2367,7 +2376,7 @@
                 int anim[] = new int[2];
                 mPolicy.selectRotationAnimationLw(anim);
 
-                startFreezingDisplayLocked(false, anim[0], anim[1], displayContent);
+                startFreezingDisplayLocked(anim[0], anim[1], displayContent);
                 config = new Configuration(mTempConfiguration);
             }
         }
@@ -2387,7 +2396,7 @@
      * tokens.
      * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
      */
-    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+    boolean updateOrientationFromAppTokensLocked(int displayId) {
         long ident = Binder.clearCallingIdentity();
         try {
             final DisplayContent dc = mRoot.getDisplayContent(displayId);
@@ -2400,7 +2409,7 @@
                 if (dc.isDefaultDisplay) {
                     mPolicy.setCurrentOrientationLw(req);
                 }
-                if (dc.updateRotationUnchecked(inTransaction)) {
+                if (dc.updateRotationUnchecked()) {
                     // changed
                     return true;
                 }
@@ -2873,7 +2882,7 @@
                 mClientFreezingScreen = true;
                 final long origId = Binder.clearCallingIdentity();
                 try {
-                    startFreezingDisplayLocked(false, exitAnim, enterAnim);
+                    startFreezingDisplayLocked(exitAnim, enterAnim);
                     mH.removeMessages(H.CLIENT_FREEZE_TIMEOUT);
                     mH.sendEmptyMessageDelayed(H.CLIENT_FREEZE_TIMEOUT, 5000);
                 } finally {
@@ -3774,8 +3783,7 @@
             if (mDeferredRotationPauseCount == 0) {
                 // TODO(multi-display): Update rotation for different displays separately.
                 final DisplayContent displayContent = getDefaultDisplayContentLocked();
-                final boolean changed = displayContent.updateRotationUnchecked(
-                        false /* inTransaction */);
+                final boolean changed = displayContent.updateRotationUnchecked();
                 if (changed) {
                     mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
                             .sendToTarget();
@@ -3800,8 +3808,7 @@
             synchronized (mWindowMap) {
                 final DisplayContent displayContent = getDefaultDisplayContentLocked();
                 Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "updateRotation: display");
-                rotationChanged = displayContent.updateRotationUnchecked(
-                        false /* inTransaction */);
+                rotationChanged = displayContent.updateRotationUnchecked();
                 Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
                 if (!rotationChanged || forceRelayout) {
                     displayContent.setLayoutNeeded();
@@ -5326,8 +5333,7 @@
         displayContent.setLayoutNeeded();
 
         final int displayId = displayContent.getDisplayId();
-        boolean configChanged = updateOrientationFromAppTokensLocked(false /* inTransaction */,
-                displayId);
+        boolean configChanged = updateOrientationFromAppTokensLocked(displayId);
         final Configuration currentDisplayConfig = displayContent.getConfiguration();
         mTempConfiguration.setTo(currentDisplayConfig);
         displayContent.computeScreenConfiguration(mTempConfiguration);
@@ -5335,7 +5341,7 @@
 
         if (configChanged) {
             mWaitingForConfig = true;
-            startFreezingDisplayLocked(false /* inTransaction */, 0 /* exitAnim */,
+            startFreezingDisplayLocked(0 /* exitAnim */,
                     0 /* enterAnim */, displayContent);
             mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayId).sendToTarget();
         }
@@ -5651,14 +5657,14 @@
         return false;
     }
 
-    void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim) {
-        startFreezingDisplayLocked(inTransaction, exitAnim, enterAnim,
+    void startFreezingDisplayLocked(int exitAnim, int enterAnim) {
+        startFreezingDisplayLocked(exitAnim, enterAnim,
                 getDefaultDisplayContentLocked());
     }
 
-    void startFreezingDisplayLocked(boolean inTransaction, int exitAnim, int enterAnim,
+    void startFreezingDisplayLocked(int exitAnim, int enterAnim,
             DisplayContent displayContent) {
-        if (mDisplayFrozen) {
+        if (mDisplayFrozen || mRotatingSeamlessly) {
             return;
         }
 
@@ -5669,8 +5675,8 @@
         }
 
         if (DEBUG_ORIENTATION) Slog.d(TAG_WM,
-                "startFreezingDisplayLocked: inTransaction=" + inTransaction
-                + " exitAnim=" + exitAnim + " enterAnim=" + enterAnim
+                "startFreezingDisplayLocked: exitAnim="
+                + exitAnim + " enterAnim=" + enterAnim
                 + " called by " + Debug.getCallers(8));
         mScreenFrozenLock.acquire();
 
@@ -5714,7 +5720,7 @@
 
             displayContent.updateDisplayInfo();
             screenRotationAnimation = new ScreenRotationAnimation(mContext, displayContent,
-                    inTransaction, mPolicy.isDefaultOrientationForced(), isSecure,
+                    mPolicy.isDefaultOrientationForced(), isSecure,
                     this);
             mAnimator.setScreenRotationAnimationLocked(mFrozenDisplayId,
                     screenRotationAnimation);
@@ -5777,9 +5783,10 @@
             if (!mPolicy.validateRotationAnimationLw(mExitAnimId, mEnterAnimId, false)) {
                 mExitAnimId = mEnterAnimId = 0;
             }
-            if (screenRotationAnimation.dismiss(MAX_ANIMATION_DURATION,
+            if (screenRotationAnimation.dismiss(mTransaction, MAX_ANIMATION_DURATION,
                     getTransitionAnimationScaleLocked(), displayInfo.logicalWidth,
                         displayInfo.logicalHeight, mExitAnimId, mEnterAnimId)) {
+                mTransaction.apply();
                 scheduleAnimationLocked();
             } else {
                 screenRotationAnimation.kill();
@@ -5802,7 +5809,7 @@
         // to avoid inconsistent states.  However, something interesting
         // could have actually changed during that time so re-evaluate it
         // now to catch that.
-        configChanged = updateOrientationFromAppTokensLocked(false, displayId);
+        configChanged = updateOrientationFromAppTokensLocked(displayId);
 
         // A little kludge: a lot could have happened while the
         // display was frozen, so now that we are coming back we
@@ -5816,8 +5823,7 @@
 
         if (updateRotation) {
             if (DEBUG_ORIENTATION) Slog.d(TAG_WM, "Performing post-rotate rotation");
-            configChanged |= displayContent.updateRotationUnchecked(
-                    false /* inTransaction */);
+            configChanged |= displayContent.updateRotationUnchecked();
         }
 
         if (configChanged) {
@@ -7027,8 +7033,10 @@
             if (DEBUG_ORIENTATION) {
                 Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
             }
+            finishSeamlessRotation();
+
             final DisplayContent displayContent = w.getDisplayContent();
-            if (displayContent.updateRotationUnchecked(false /* inTransaction */)) {
+            if (displayContent.updateRotationUnchecked()) {
                 mH.obtainMessage(H.SEND_NEW_CONFIGURATION, displayContent.getDisplayId())
                         .sendToTarget();
             }
@@ -7439,6 +7447,18 @@
                 .sendToTarget();
     }
 
+    void startSeamlessRotation() {
+        // We are careful to reset this in case a window was removed before it finished
+        // seamless rotation.
+        mSeamlessRotationCount = 0;
+
+        mRotatingSeamlessly = true;
+    }
+
+    void finishSeamlessRotation() {
+        mRotatingSeamlessly = false;
+    }
+
     /**
      * Called when the state of lock task mode changes. This should be used to disable immersive
      * mode confirmation.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 68bb530..8866fe5 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2015,7 +2015,7 @@
             removeImmediately();
             // Removing a visible window will effect the computed orientation
             // So just update orientation if needed.
-            if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) {
+            if (wasVisible && mService.updateOrientationFromAppTokensLocked(displayId)) {
                 mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
             }
             mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 13f05e0..46a9961 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1415,7 +1415,8 @@
         }
     }
 
-    void seamlesslyRotateWindow(int oldRotation, int newRotation) {
+    void seamlesslyRotateWindow(SurfaceControl.Transaction t,
+            int oldRotation, int newRotation) {
         final WindowState w = mWin;
         if (!w.isVisibleNow() || w.mIsWallpaper) {
             return;
@@ -1456,11 +1457,9 @@
         float DsDy = mService.mTmpFloats[Matrix.MSCALE_Y];
         float nx = mService.mTmpFloats[Matrix.MTRANS_X];
         float ny = mService.mTmpFloats[Matrix.MTRANS_Y];
-        mSurfaceController.setPositionInTransaction(nx, ny, false);
-        mSurfaceController.setMatrixInTransaction(DsDx * w.mHScale,
-                DtDx * w.mVScale,
-                DtDy * w.mHScale,
-                DsDy * w.mVScale, false);
+        mSurfaceController.setPosition(t, nx, ny, false);
+        mSurfaceController.setMatrix(t, DsDx * w.mHScale, DtDx * w.mVScale, DtDy
+                * w.mHScale, DsDy * w.mVScale, false);
     }
 
     /** The force-scaled state for a given window can persist past
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 9d6f8f7..f6c0a54 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -242,6 +242,11 @@
     }
 
     void setPositionInTransaction(float left, float top, boolean recoveringMemory) {
+        setPosition(null, left, top, recoveringMemory);
+    }
+
+    void setPosition(SurfaceControl.Transaction t, float left, float top,
+            boolean recoveringMemory) {
         final boolean surfaceMoved = mSurfaceX != left || mSurfaceY != top;
         if (surfaceMoved) {
             mSurfaceX = left;
@@ -251,7 +256,11 @@
                 if (SHOW_TRANSACTIONS) logSurface(
                         "POS (setPositionInTransaction) @ (" + left + "," + top + ")", null);
 
-                mSurfaceControl.setPosition(left, top);
+                if (t == null) {
+                    mSurfaceControl.setPosition(left, top);
+                } else {
+                    t.setPosition(mSurfaceControl, left, top);
+                }
             } catch (RuntimeException e) {
                 Slog.w(TAG, "Error positioning surface of " + this
                         + " pos=(" + left + "," + top + ")", e);
@@ -268,6 +277,11 @@
 
     void setMatrixInTransaction(float dsdx, float dtdx, float dtdy, float dsdy,
             boolean recoveringMemory) {
+        setMatrix(null, dsdx, dtdx, dtdy, dsdy, false);
+    }
+
+    void setMatrix(SurfaceControl.Transaction t, float dsdx, float dtdx,
+            float dtdy, float dsdy, boolean recoveringMemory) {
         final boolean matrixChanged = mLastDsdx != dsdx || mLastDtdx != dtdx ||
                                       mLastDtdy != dtdy || mLastDsdy != dsdy;
         if (!matrixChanged) {
@@ -282,8 +296,11 @@
         try {
             if (SHOW_TRANSACTIONS) logSurface(
                     "MATRIX [" + dsdx + "," + dtdx + "," + dtdy + "," + dsdy + "]", null);
-            mSurfaceControl.setMatrix(
-                    dsdx, dtdx, dtdy, dsdy);
+            if (t == null) {
+                mSurfaceControl.setMatrix(dsdx, dtdx, dtdy, dsdy);
+            } else {
+                t.setMatrix(mSurfaceControl, dsdx, dtdx, dtdy, dsdy);
+            }
         } catch (RuntimeException e) {
             // If something goes wrong with the surface (such
             // as running out of memory), don't take down the
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ab8a6c4..83c9f7c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12658,8 +12658,7 @@
         final DeviceAdminInfo incomingDeviceInfo = findAdmin(target, callingUserId,
                 /* throwForMissingPermission= */ true);
         checkActiveAdminPrecondition(target, incomingDeviceInfo, policy);
-        if (!incomingDeviceInfo.getActivityInfo().metaData
-                .getBoolean(DeviceAdminReceiver.SUPPORT_TRANSFER_OWNERSHIP_META_DATA, false)) {
+        if (!incomingDeviceInfo.supportsTransferOwnership()) {
             throw new IllegalArgumentException("Provided target does not support "
                     + "ownership transfer.");
         }
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
index 86c83d6..d37db20 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
@@ -18,9 +18,14 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.os.Process;
 import android.platform.test.annotations.Presubmit;
@@ -30,6 +35,7 @@
 import com.android.server.backup.BackupManagerService;
 import com.android.server.backup.testutils.PackageManagerStub;
 
+import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -45,7 +51,14 @@
     private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
     private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
 
-    private final PackageManagerStub mPackageManagerStub = new PackageManagerStub();
+    private PackageManagerStub mPackageManagerStub;
+    private PackageManagerInternal mMockPackageManagerInternal;
+
+    @Before
+    public void setUp() throws Exception {
+        mPackageManagerStub = new PackageManagerStub();
+        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
+    }
 
     @Test
     public void appIsEligibleForBackup_backupNotAllowed_returnsFalse() throws Exception {
@@ -358,7 +371,8 @@
 
     @Test
     public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
-        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null);
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -366,10 +380,12 @@
     @Test
     public void signaturesMatch_systemApplication_returnsTrue() throws Exception {
         PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
 
-        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isTrue();
     }
@@ -378,10 +394,12 @@
     public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse()
             throws Exception {
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[] {SIGNATURE_1};
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
         packageInfo.applicationInfo = new ApplicationInfo();
 
-        boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+        boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -390,10 +408,12 @@
     public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse()
             throws Exception {
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[] {SIGNATURE_1};
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
         packageInfo.applicationInfo = new ApplicationInfo();
 
-        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -404,11 +424,12 @@
     signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse()
             throws Exception {
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[0];
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[0][0];
         packageInfo.applicationInfo = new ApplicationInfo();
 
-        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1},
-                packageInfo);
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -418,11 +439,12 @@
     signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse()
             throws Exception {
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = null;
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = null;
         packageInfo.applicationInfo = new ApplicationInfo();
 
-        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1},
-                packageInfo);
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -431,10 +453,11 @@
     public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse()
             throws Exception {
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = null;
+        packageInfo.signingCertificateHistory = null;
         packageInfo.applicationInfo = new ApplicationInfo();
 
-        boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+        boolean result = AppBackupUtils.signaturesMatch(null, packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -443,10 +466,12 @@
     public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse()
             throws Exception {
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[0];
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[0][0];
         packageInfo.applicationInfo = new ApplicationInfo();
 
-        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -458,11 +483,15 @@
         Signature signature3Copy = new Signature(SIGNATURE_3.toByteArray());
 
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {
+                {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+        };
         packageInfo.applicationInfo = new ApplicationInfo();
 
         boolean result = AppBackupUtils.signaturesMatch(
-                new Signature[]{signature3Copy, signature1Copy, signature2Copy}, packageInfo);
+                new Signature[] {signature3Copy, signature1Copy, signature2Copy}, packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isTrue();
     }
@@ -473,11 +502,15 @@
         Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
 
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {
+                {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+        };
         packageInfo.applicationInfo = new ApplicationInfo();
 
         boolean result = AppBackupUtils.signaturesMatch(
-                new Signature[]{signature2Copy, signature1Copy}, packageInfo);
+                new Signature[]{signature2Copy, signature1Copy}, packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isTrue();
     }
@@ -488,11 +521,15 @@
         Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
 
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[]{signature1Copy, signature2Copy};
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {
+                {signature1Copy, signature2Copy}
+        };
         packageInfo.applicationInfo = new ApplicationInfo();
 
         boolean result = AppBackupUtils.signaturesMatch(
-                new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo);
+                new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo,
+                mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
@@ -503,11 +540,77 @@
         Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray());
 
         PackageInfo packageInfo = new PackageInfo();
-        packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3};
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {
+                {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+        };
         packageInfo.applicationInfo = new ApplicationInfo();
 
         boolean result = AppBackupUtils.signaturesMatch(
-                new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo);
+                new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue()
+            throws Exception {
+        Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+                packageInfo.packageName);
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+                packageInfo, mMockPackageManagerInternal);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue()
+            throws Exception {
+        Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        // we know signature1Copy is in history, and we want to assume it has
+        // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+                packageInfo.packageName);
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+                packageInfo, mMockPackageManagerInternal);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void
+            signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse()
+            throws Exception {
+        Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray());
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        // we know signature1Copy is in history, but we want to assume it does not have
+        // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+        doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy,
+                packageInfo.packageName);
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy},
+                packageInfo, mMockPackageManagerInternal);
 
         assertThat(result).isFalse();
     }
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
index 0cdf04b..5f052ce 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java
@@ -28,6 +28,9 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
@@ -37,6 +40,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.os.Bundle;
 import android.os.Process;
@@ -79,6 +83,7 @@
 
     @Mock private BytesReadListener mBytesReadListenerMock;
     @Mock private IBackupManagerMonitor mBackupManagerMonitorMock;
+    @Mock private PackageManagerInternal mMockPackageManagerInternal;
 
     private final PackageManagerStub mPackageManagerStub = new PackageManagerStub();
     private Context mContext;
@@ -139,7 +144,8 @@
         Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures(
                 fileMetadata);
         RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy(
-                mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+                mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
+                mMockPackageManagerInternal);
 
         assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
         assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -152,7 +158,8 @@
         signatures = tarBackupReader.readAppManifestAndReturnSignatures(
                 fileMetadata);
         restorePolicy = tarBackupReader.chooseRestorePolicy(
-                mPackageManagerStub, false /* allowApks */, fileMetadata, signatures);
+                mPackageManagerStub, false /* allowApks */, fileMetadata, signatures,
+                mMockPackageManagerInternal);
 
         assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE);
         assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME);
@@ -214,7 +221,8 @@
                 mBytesReadListenerMock, mBackupManagerMonitorMock);
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                true /* allowApks */, new FileMetadata(), null /* signatures */);
+                true /* allowApks */, new FileMetadata(), null /* signatures */,
+                mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         verifyZeroInteractions(mBackupManagerMonitorMock);
@@ -234,7 +242,8 @@
         PackageManagerStub.sPackageInfo = null;
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                true /* allowApks */, info, new Signature[0] /* signatures */);
+                true /* allowApks */, info, new Signature[0] /* signatures */,
+                mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -258,7 +267,8 @@
         PackageManagerStub.sPackageInfo = null;
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                true /* allowApks */, info, new Signature[0] /* signatures */);
+                true /* allowApks */, info, new Signature[0] /* signatures */,
+                mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -283,7 +293,8 @@
         PackageManagerStub.sPackageInfo = null;
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+                false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+                mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -307,7 +318,8 @@
         PackageManagerStub.sPackageInfo = packageInfo;
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+                false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+                mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -333,7 +345,8 @@
         PackageManagerStub.sPackageInfo = packageInfo;
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */);
+                false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */,
+                mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -358,11 +371,11 @@
         packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
-        packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_2};
+        packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_2}};
         PackageManagerStub.sPackageInfo = packageInfo;
 
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), signatures);
+                false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -383,16 +396,19 @@
         Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1};
 
         PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.flags |=
                 ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
         packageInfo.applicationInfo.uid = Process.SYSTEM_UID;
         packageInfo.applicationInfo.backupAgentName = "backup.agent";
-        packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+        packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
         PackageManagerStub.sPackageInfo = packageInfo;
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+                packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), signatures);
+                false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -412,16 +428,19 @@
         Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1};
 
         PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.flags |=
                 ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
-        packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+        packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
         PackageManagerStub.sPackageInfo = packageInfo;
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+                packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, new FileMetadata(), signatures);
+                false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -444,17 +463,20 @@
         info.version = 1;
 
         PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
-        packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+        packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
         packageInfo.versionCode = 2;
         PackageManagerStub.sPackageInfo = packageInfo;
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+                packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, info, signatures);
+                false /* allowApks */, info, signatures, mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
@@ -479,17 +501,20 @@
         info.hasApk = true;
 
         PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
-        packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+        packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
         packageInfo.versionCode = 1;
         PackageManagerStub.sPackageInfo = packageInfo;
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+                packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                true /* allowApks */, info, signatures);
+                true /* allowApks */, info, signatures, mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK);
         verifyNoMoreInteractions(mBackupManagerMonitorMock);
@@ -510,17 +535,20 @@
         info.version = 2;
 
         PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
         packageInfo.applicationInfo = new ApplicationInfo();
         packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION;
         packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         packageInfo.applicationInfo.backupAgentName = null;
-        packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1};
+        packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}};
         packageInfo.versionCode = 1;
         PackageManagerStub.sPackageInfo = packageInfo;
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1,
+                packageInfo.packageName);
         RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub,
-                false /* allowApks */, info, signatures);
+                false /* allowApks */, info, signatures, mMockPackageManagerInternal);
 
         assertThat(policy).isEqualTo(RestorePolicy.IGNORE);
         ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
index 1211f00..2f2afd7 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -44,6 +44,7 @@
 import static org.mockito.Matchers.any;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.mock;
 
 @SmallTest
 public class DisplayManagerServiceTest extends AndroidTestCase {
@@ -123,7 +124,7 @@
                 "Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
                 uniqueId);
 
-        displayManager.performTraversalInTransactionFromWindowManagerInternal();
+        displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
 
         // flush the handler
         displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
@@ -161,7 +162,7 @@
                 "Test Virtual Display", width, height, dpi, null /* surface */, flags /* flags */,
                 uniqueId);
 
-        displayManager.performTraversalInTransactionFromWindowManagerInternal();
+        displayManager.performTraversalInternal(mock(SurfaceControl.Transaction.class));
 
         // flush the handler
         displayManager.getDisplayHandler().runWithScissors(() -> {}, 0 /* now */);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 51d27fe..1974750 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1015,7 +1015,8 @@
                 | ApplicationInfo.FLAG_ALLOW_BACKUP;
         pi.versionCode = version;
         pi.applicationInfo.versionCode = version;
-        pi.signatures = genSignatures(signatures);
+        pi.signatures = null;
+        pi.signingCertificateHistory = new Signature[][] {genSignatures(signatures)};
 
         return pi;
     }
@@ -1103,7 +1104,8 @@
                 !mDisabledPackages.contains(PackageWithUser.of(userId, packageName));
 
         if (getSignatures) {
-            ret.signatures = pi.signatures;
+            ret.signatures = null;
+            ret.signingCertificateHistory = pi.signingCertificateHistory;
         }
 
         return ret;
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 845e05d..7815004 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -62,6 +62,7 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -3987,6 +3988,10 @@
         if (!nowBackupAllowed) {
             pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP;
         }
+
+        doReturn(expected != DISABLED_REASON_SIGNATURE_MISMATCH).when(
+                mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class), anyString());
+
         assertEquals(expected, spi.canRestoreTo(mService, pi, anyVersionOk));
     }
 
@@ -4959,6 +4964,9 @@
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+                anyString());
+
         installPackage(USER_0, CALLING_PACKAGE_1);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertWith(getCallerVisibleShortcuts())
@@ -5151,6 +5159,10 @@
 
     protected void checkBackupAndRestore_publisherNotRestored(
             int package1DisabledReason) {
+        doReturn(package1DisabledReason != ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH).when(
+                mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+                eq(CALLING_PACKAGE_1));
+
         installPackage(USER_0, CALLING_PACKAGE_1);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5159,6 +5171,8 @@
         assertFalse(mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0)
                 .getPackageInfo().isShadow());
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+                any(byte[].class), anyString());
 
         installPackage(USER_0, CALLING_PACKAGE_2);
         runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
@@ -5276,7 +5290,7 @@
 
         addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "sigx"); // different signature
 
-        checkBackupAndRestore_launcherNotRestored();
+        checkBackupAndRestore_launcherNotRestored(true);
     }
 
     public void testBackupAndRestore_launcherNoLongerBackupTarget() {
@@ -5285,10 +5299,13 @@
         updatePackageInfo(LAUNCHER_1,
                 pi -> pi.applicationInfo.flags &= ~ApplicationInfo.FLAG_ALLOW_BACKUP);
 
-        checkBackupAndRestore_launcherNotRestored();
+        checkBackupAndRestore_launcherNotRestored(false);
     }
 
-    protected void checkBackupAndRestore_launcherNotRestored() {
+    protected void checkBackupAndRestore_launcherNotRestored(boolean differentSignatures) {
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+                any(byte[].class), anyString());
+
         installPackage(USER_0, CALLING_PACKAGE_1);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5307,6 +5324,9 @@
                     "s1", "s2", "s3");
         });
 
+        doReturn(!differentSignatures).when(mMockPackageManagerInternal).isDataRestoreSafe(
+                any(byte[].class), eq(LAUNCHER_1));
+
         // Now we try to restore launcher 1.  Then we realize it's not restorable, so L1 has no pinned
         // shortcuts.
         installPackage(USER_0, LAUNCHER_1);
@@ -5333,6 +5353,9 @@
                     "s2");
         });
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+                any(byte[].class), anyString());
+
         installPackage(USER_0, LAUNCHER_2);
         runWithCaller(LAUNCHER_2, USER_0, () -> {
             assertShortcutIds(assertAllPinned(
@@ -5388,6 +5411,8 @@
     }
 
     protected void checkBackupAndRestore_publisherAndLauncherNotRestored() {
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+                anyString());
         installPackage(USER_0, CALLING_PACKAGE_1);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertEquals(0, mManager.getDynamicShortcuts().size());
@@ -5501,6 +5526,9 @@
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_0, LAUNCHER_3)));
         assertNull(user0.getAllLaunchersForTest().get(PackageWithUser.of(USER_P0, LAUNCHER_1)));
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+                anyString());
+
         installPackage(USER_0, CALLING_PACKAGE_1);
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
             assertWith(getCallerVisibleShortcuts())
@@ -5586,6 +5614,8 @@
                     .areAllDisabled();
         });
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+                any(byte[].class), anyString());
         backupAndRestore();
 
         // When re-installing the app, the manifest shortcut should be re-published.
@@ -5695,6 +5725,8 @@
                     .haveIds("s1", "ms1");
         });
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(any(byte[].class),
+                anyString());
         // Backup and *without restarting the service, just call applyRestore()*.
         {
             int prevUid = mInjectedCallingUid;
@@ -5768,6 +5800,9 @@
                     list("ms1", "ms2", "ms3", "ms4", "s1", "s2"), HANDLE_USER_0);
         });
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+                any(byte[].class), anyString());
+
         backupAndRestore();
 
         // Lower the version and remove the manifest shortcuts.
@@ -5994,6 +6029,9 @@
         addPackage(CALLING_PACKAGE_1, CALLING_UID_1, 10, "22222");
         addPackage(LAUNCHER_1, LAUNCHER_UID_1, 10, "11111");
 
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(
+                any(byte[].class), anyString());
+
         runWithSystemUid(() -> mService.applyRestore(payload, USER_0));
 
         runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
index 29c98dc..cd7feea 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest5.java
@@ -76,11 +76,13 @@
                 mMyPackage, mMyUserId, /*signature*/ false);
         assertEquals(mMyPackage, pi.packageName);
         assertNull(pi.signatures);
+        assertNull(pi.signingCertificateHistory);
 
         pi = mShortcutService.getPackageInfo(
                 mMyPackage, mMyUserId, /*signature*/ true);
         assertEquals(mMyPackage, pi.packageName);
-        assertNotNull(pi.signatures);
+        assertNull(pi.signatures);
+        assertNotNull(pi.signingCertificateHistory);
 
         pi = mShortcutService.getPackageInfo(
                 "no.such.package", mMyUserId, /*signature*/ true);
diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
index c016e61..1ac7cb8 100644
--- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java
@@ -15,73 +15,309 @@
  */
 package com.android.server.pm.backup;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
+import android.content.pm.PackageManagerInternal;
 import android.content.pm.PackageParser.Package;
 import android.content.pm.Signature;
-import android.test.AndroidTestCase;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import com.android.server.backup.BackupUtils;
 
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 
 @SmallTest
-public class BackupUtilsTest extends AndroidTestCase {
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class BackupUtilsTest {
 
-    private Signature[] genSignatures(String... signatures) {
-        final Signature[] sigs = new Signature[signatures.length];
-        for (int i = 0; i < signatures.length; i++){
-            sigs[i] = new Signature(signatures[i].getBytes());
-        }
-        return sigs;
+    private static final Signature SIGNATURE_1 = generateSignature((byte) 1);
+    private static final Signature SIGNATURE_2 = generateSignature((byte) 2);
+    private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
+    private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
+    private static final byte[] SIGNATURE_HASH_1 = BackupUtils.hashSignature(SIGNATURE_1);
+    private static final byte[] SIGNATURE_HASH_2 = BackupUtils.hashSignature(SIGNATURE_2);
+    private static final byte[] SIGNATURE_HASH_3 = BackupUtils.hashSignature(SIGNATURE_3);
+    private static final byte[] SIGNATURE_HASH_4 = BackupUtils.hashSignature(SIGNATURE_4);
+
+    private PackageManagerInternal mMockPackageManagerInternal;
+
+    @Before
+    public void setUp() throws Exception {
+        mMockPackageManagerInternal = mock(PackageManagerInternal.class);
     }
 
-    private PackageInfo genPackage(String... signatures) {
-        final PackageInfo pi = new PackageInfo();
-        pi.packageName = "package";
-        pi.applicationInfo = new ApplicationInfo();
-        pi.signatures = genSignatures(signatures);
+    @Test
+    public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, null,
+                mMockPackageManagerInternal);
 
-        return pi;
+        assertThat(result).isFalse();
     }
 
-    public void testSignaturesMatch() {
-        final ArrayList<byte[]> stored1 = BackupUtils.hashSignatureArray(Arrays.asList(
-                "abc".getBytes()));
-        final ArrayList<byte[]> stored2 = BackupUtils.hashSignatureArray(Arrays.asList(
-                "abc".getBytes(), "def".getBytes()));
+    @Test
+    public void signaturesMatch_systemApplication_returnsTrue() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
 
-        PackageInfo pi;
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
 
-        // False for null package.
-        assertFalse(BackupUtils.signaturesMatch(stored1, null));
-
-        // If it's a system app, signatures don't matter.
-        pi = genPackage("xyz");
-        pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
-        assertTrue(BackupUtils.signaturesMatch(stored1, pi));
-
-        // Non system apps.
-        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc")));
-
-        // Superset is okay.
-        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz")));
-        assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc")));
-
-        assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz")));
-        assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def")));
-
-        assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc")));
-        assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y")));
-
-        // Subset is not okay.
-        assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc")));
-        assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def")));
+        assertThat(result).isTrue();
     }
 
+    @Test
+    public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = BackupUtils.signaturesMatch(null, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+
+    @Test
+    public void
+    signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[0][0];
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void
+    signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = null;
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = null;
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = BackupUtils.signaturesMatch(null, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[0][0];
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_equalSignatures_returnsTrue() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {
+                {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+        };
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        storedSigHashes.add(SIGNATURE_HASH_2);
+        storedSigHashes.add(SIGNATURE_HASH_3);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {
+                {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+        };
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        storedSigHashes.add(SIGNATURE_HASH_2);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1, SIGNATURE_2}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        storedSigHashes.add(SIGNATURE_HASH_2);
+        storedSigHashes.add(SIGNATURE_HASH_3);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {
+                {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}
+        };
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        storedSigHashes.add(SIGNATURE_HASH_2);
+        storedSigHashes.add(SIGNATURE_HASH_4);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+                packageInfo.packageName);
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        // we know SIGNATURE_1 is in history, and we want to assume it has
+        // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+        doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+                packageInfo.packageName);
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void
+            signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.packageName = "test";
+        packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        // we know SIGNATURE_1 is in history, but we want to assume it does not have
+        // SigningDetails.CertCapabilities.INSTALLED_DATA capability
+        doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1,
+                packageInfo.packageName);
+
+        ArrayList<byte[]> storedSigHashes = new ArrayList<>();
+        storedSigHashes.add(SIGNATURE_HASH_1);
+        boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo,
+                mMockPackageManagerInternal);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
     public void testHashSignature() {
         final byte[] sig1 = "abc".getBytes();
         final byte[] sig2 = "def".getBytes();
@@ -115,4 +351,10 @@
         MoreAsserts.assertEquals(hash2a, listA.get(1));
         MoreAsserts.assertEquals(hash2a, listB.get(1));
     }
+
+    private static Signature generateSignature(byte i) {
+        byte[] signatureBytes = new byte[256];
+        signatureBytes[0] = i;
+        return new Signature(signatureBytes);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
index b36c7d9..edac8a5 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimationRunnerTest.java
@@ -169,6 +169,7 @@
         verify(mMockAnimationSpec, atLeastOnce()).apply(any(), any(), eq(0L));
     }
 
+    @FlakyTest(bugId = 74780584)
     @Test
     public void testDeferStartingAnimations() throws Exception {
         mSurfaceAnimationRunner.deferStartingAnimations();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7add893..4a0027b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5183,7 +5183,7 @@
             ITelephony telephony = getITelephony();
             if (telephony == null)
                 return null;
-            return telephony.getForbiddenPlmns(subId, appType);
+            return telephony.getForbiddenPlmns(subId, appType, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index afbb947..7c7700b 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1444,13 +1444,12 @@
      * Returns a list of Forbidden PLMNs from the specified SIM App
      * Returns null if the query fails.
      *
-     *
-     * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
+     * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE or READ_PHONE_STATE
      *
      * @param subId subscription ID used for authentication
      * @param appType the icc application type, like {@link #APPTYPE_USIM}
      */
-    String[] getForbiddenPlmns(int subId, int appType);
+    String[] getForbiddenPlmns(int subId, int appType, String callingPackage);
 
     /**
      * Check if phone is in emergency callback mode
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index a3a3080..ee7084ad 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -25,6 +25,7 @@
  */
 
 import android.os.SystemProperties;
+import android.telephony.TelephonyManager;
 
 /**
  * {@hide}
@@ -162,8 +163,8 @@
     int NETWORK_MODE_LTE_TDSCDMA_GSM_WCDMA   = 20; /* TD-SCDMA, GSM/WCDMA and LTE */
     int NETWORK_MODE_TDSCDMA_CDMA_EVDO_GSM_WCDMA  = 21; /*TD-SCDMA,EvDo,CDMA,GSM/WCDMA*/
     int NETWORK_MODE_LTE_TDSCDMA_CDMA_EVDO_GSM_WCDMA = 22; /* TD-SCDMA/LTE/GSM/WCDMA, CDMA, and EvDo */
-    int PREFERRED_NETWORK_MODE      = SystemProperties.getInt("ro.telephony.default_network",
-            NETWORK_MODE_WCDMA_PREF);
+    int PREFERRED_NETWORK_MODE = Integer.parseInt(TelephonyManager.getTelephonyProperty(0,
+            "ro.telephony.default_network", Integer.toString(NETWORK_MODE_WCDMA_PREF)));
 
     int BAND_MODE_UNSPECIFIED = 0;      //"unspecified" (selected by baseband automatically)
     int BAND_MODE_EURO = 1;             //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 93fa598..6865f77 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -86,9 +86,6 @@
         /** WPA is not used; plaintext or static WEP could be used. */
         public static final int NONE = 0;
         /** WPA pre-shared key (requires {@code preSharedKey} to be specified). */
-        /** @deprecated Due to security and performance limitations, use of WPA-1 networks
-         * is discouraged. WPA-2 (RSN) should be used instead. */
-        @Deprecated
         public static final int WPA_PSK = 1;
         /** WPA using EAP authentication. Generally used with an external authentication server. */
         public static final int WPA_EAP = 2;
@@ -122,7 +119,7 @@
 
         public static final String varName = "key_mgmt";
 
-        public static final String[] strings = { "NONE", /* deprecated */ "WPA_PSK", "WPA_EAP",
+        public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP",
                 "IEEE8021X", "WPA2_PSK", "OSEN", "FT_PSK", "FT_EAP" };
     }
 
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index eca84064..ebf6007 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -133,7 +133,8 @@
      *                    match filter. For {@link PublishConfig#PUBLISH_TYPE_SOLICITED},
      *                    {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE} discovery sessions this
      *                    is the subscriber's match filter.
-     * @param distanceMm The measured distance to the Publisher in mm.
+     * @param distanceMm The measured distance to the Publisher in mm. Note: the measured distance
+     *                   may be negative for very close devices.
      */
     public void onServiceDiscoveredWithinRange(PeerHandle peerHandle,
         byte[] serviceSpecificInfo, List<byte[]> matchFilter, int distanceMm) {
diff --git a/wifi/java/android/net/wifi/rtt/RangingResult.java b/wifi/java/android/net/wifi/rtt/RangingResult.java
index 4705e1d..7fe85be 100644
--- a/wifi/java/android/net/wifi/rtt/RangingResult.java
+++ b/wifi/java/android/net/wifi/rtt/RangingResult.java
@@ -147,6 +147,8 @@
      * @return The distance (in mm) to the device specified by {@link #getMacAddress()} or
      * {@link #getPeerHandle()}.
      * <p>
+     * Note: the measured distance may be negative for very close devices.
+     * <p>
      * Only valid if {@link #getStatus()} returns {@link #STATUS_SUCCESS}, otherwise will throw an
      * exception.
      */