Merge "Move focus dispatch to input (1/2)"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5186ad3..cf75bba 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -854,7 +854,6 @@
             tags |= c.tags;
         }
     }
-    ok &= setTagsProperty(tags);
 
     bool coreServicesTagEnabled = false;
     for (size_t i = 0; i < arraysize(k_categories); i++) {
@@ -876,9 +875,11 @@
         packageList += android::base::GetProperty(k_coreServicesProp, "");
     }
     ok &= setAppCmdlineProperty(&packageList[0]);
+    ok &= setTagsProperty(tags);
+#if !ATRACE_SHMEM
     ok &= pokeBinderServices();
     pokeHalServices();
-
+#endif
     if (g_tracePdx) {
         ok &= ServiceUtility::PokeServices();
     }
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 6b14bee..a10baa6 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -108,6 +108,8 @@
  * Property to control if app data isolation is enabled.
  */
 static constexpr const char* kAppDataIsolationEnabledProperty = "persist.zygote.app_data_isolation";
+static constexpr const char* kMntSdcardfs = "/mnt/runtime/default/";
+static constexpr const char* kMntFuse = "/mnt/pass_through/0/";
 
 static std::atomic<bool> sAppDataIsolationEnabled(false);
 
@@ -2686,15 +2688,13 @@
         std::getline(in, ignored);
 
         if (android::base::GetBoolProperty(kFuseProp, false)) {
-            // TODO(b/146139106): Use sdcardfs mounts on devices running sdcardfs so we don't bypass
-            // it's VFS cache
-            if (target.compare(0, 17, "/mnt/pass_through") == 0) {
+            if (target.find(kMntFuse) == 0) {
                 LOG(DEBUG) << "Found storage mount " << source << " at " << target;
                 mStorageMounts[source] = target;
             }
         } else {
 #if !BYPASS_SDCARDFS
-            if (target.compare(0, 21, "/mnt/runtime/default/") == 0) {
+            if (target.find(kMntSdcardfs) == 0) {
                 LOG(DEBUG) << "Found storage mount " << source << " at " << target;
                 mStorageMounts[source] = target;
             }
@@ -2792,17 +2792,6 @@
     std::lock_guard<std::recursive_mutex> lock(mMountsLock);
     const char* uuid_ = uuid ? uuid->c_str() : nullptr;
     auto path = StringPrintf("%s/media", create_data_path(uuid_).c_str());
-    if (android::base::GetBoolProperty(kFuseProp, false)) {
-        // TODO(b/146139106): This is only safe on devices not running sdcardfs where there is no
-        // risk of bypassing the sdcardfs VFS cache
-
-        // Always use the lower filesystem path on FUSE enabled devices not running sdcardfs
-        // The upper filesystem path, /mnt/pass_through/<userid>/<vol>/ which was a bind mount
-        // to the lower filesytem may have been unmounted already when a user is
-        // removed and the path will now be pointing to a tmpfs without content
-        return StringPrintf("%s/%u", path.c_str(), userid);
-    }
-
     auto resolved = mStorageMounts[path];
     if (resolved.empty()) {
         LOG(WARNING) << "Failed to find storage mount for " << path;
diff --git a/cmds/surfacereplayer/replayer/Replayer.cpp b/cmds/surfacereplayer/replayer/Replayer.cpp
index 0d6c31e..675aad6 100644
--- a/cmds/surfacereplayer/replayer/Replayer.cpp
+++ b/cmds/surfacereplayer/replayer/Replayer.cpp
@@ -606,7 +606,7 @@
             pc.viewport().bottom());
     Rect frame = Rect(pc.frame().left(), pc.frame().top(), pc.frame().right(), pc.frame().bottom());
 
-    t.setDisplayProjection(mDisplays[id], pc.orientation(), viewport, frame);
+    t.setDisplayProjection(mDisplays[id], ui::toRotation(pc.orientation()), viewport, frame);
 }
 
 status_t Replayer::createSurfaceControl(
diff --git a/include/android/bitmap.h b/include/android/bitmap.h
index 01cf2f8..41718b2 100644
--- a/include/android/bitmap.h
+++ b/include/android/bitmap.h
@@ -100,6 +100,19 @@
 int AndroidBitmap_getInfo(JNIEnv* env, jobject jbitmap,
                           AndroidBitmapInfo* info);
 
+#if __ANDROID_API__ >= 30
+
+/**
+ * Given a java bitmap object, return its ADataSpace.
+ *
+ * Note that ADataSpace only exposes a few values. This may return
+ * ADATASPACE_UNKNOWN, even for Named ColorSpaces, if they have no
+ * corresponding ADataSpace.
+ */
+int32_t AndroidBitmap_getDataSpace(JNIEnv* env, jobject jbitmap)  __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
 /**
  * Given a java bitmap object, attempt to lock the pixel address.
  * Locking will ensure that the memory for the pixels will not move
diff --git a/include/android/imagedecoder.h b/include/android/imagedecoder.h
new file mode 100644
index 0000000..50daaba
--- /dev/null
+++ b/include/android/imagedecoder.h
@@ -0,0 +1,299 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/**
+ * @addtogroup ImageDecoder
+ * @{
+ */
+
+/**
+ * @file imageDecoder.h
+ */
+
+#ifndef ANDROID_IMAGE_DECODER_H
+#define ANDROID_IMAGE_DECODER_H
+
+#include "bitmap.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct AAsset;
+struct ARect;
+
+#if __ANDROID_API__ >= 30
+
+/** AImageDecoder functions result code. */
+enum {
+    // Decoding was successful and complete.
+    ANDROID_IMAGE_DECODER_SUCCESS = 0,
+    // The input was incomplete. In decodeImage, this means a partial
+    // image was decoded. Undecoded lines are all zeroes.
+    // In AImageDecoder_create*, no AImageDecoder was created.
+    ANDROID_IMAGE_DECODER_INCOMPLETE = -1,
+    // The input contained an error after decoding some lines. Similar to
+    // INCOMPLETE, above.
+    ANDROID_IMAGE_DECODER_ERROR = -2,
+    // Could not convert, e.g. attempting to decode an image with
+    // alpha to an opaque format.
+    ANDROID_IMAGE_DECODER_INVALID_CONVERSION = -3,
+    // The scale is invalid. It may have overflowed, or it may be incompatible
+    // with the current alpha setting.
+    ANDROID_IMAGE_DECODER_INVALID_SCALE = -4,
+    // Some other parameter was bad (e.g. pixels)
+    ANDROID_IMAGE_DECODER_BAD_PARAMETER = -5,
+    // Input was invalid i.e. broken before decoding any pixels.
+    ANDROID_IMAGE_DECODER_INVALID_INPUT = -6,
+    // A seek was required, and failed.
+    ANDROID_IMAGE_DECODER_SEEK_ERROR = -7,
+    // Some other error (e.g. OOM)
+    ANDROID_IMAGE_DECODER_INTERNAL_ERROR = -8,
+    // We did not recognize the format
+    ANDROID_IMAGE_DECODER_UNSUPPORTED_FORMAT = -9
+};
+
+struct AImageDecoder;
+
+/**
+ * Opaque handle for decoding images.
+ *
+ * Create using one of the following:
+ * - {@link AImageDecoder_createFromAAsset}
+ * - {@link AImageDecoder_createFromFd}
+ * - {@link AImageDecoder_createFromBuffer}
+ */
+typedef struct AImageDecoder AImageDecoder;
+
+/**
+ * Create a new AImageDecoder from an AAsset.
+ *
+ * @param asset {@link AAsset} containing encoded image data. Client is still
+ *              responsible for calling {@link AAsset_close} on it.
+ * @param outDecoder On success (i.e. return value is
+ *                   {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ *                   a newly created {@link AImageDecoder}. Caller is
+ *                   responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ *         indicating reason for the failure.
+ */
+int AImageDecoder_createFromAAsset(AAsset* asset, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+
+/**
+ * Create a new AImageDecoder from a file descriptor.
+ *
+ * @param fd Seekable, readable, open file descriptor for encoded data.
+ *           Client is still responsible for closing it, which may be done
+ *           *after* deleting the returned AImageDecoder.
+ * @param outDecoder On success (i.e. return value is
+ *                   {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ *                   a newly created {@link AImageDecoder}. Caller is
+ *                   responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ *         indicating reason for the failure.
+ */
+int AImageDecoder_createFromFd(int fd, AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+
+/**
+ * Create a new AImageDecoder from a buffer.
+ *
+ * @param buffer Pointer to encoded data. Must be valid for the entire time
+ *               the AImageDecoder is used.
+ * @param length Byte length of buffer.
+ * @param outDecoder On success (i.e. return value is
+ *                   {@link ANDROID_IMAGE_DECODER_SUCCESS}), this will be set to
+ *                   a newly created {@link AImageDecoder}. Caller is
+ *                   responsible for calling {@link AImageDecoder_delete} on it.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success or a value
+ *         indicating reason for the failure.
+ */
+int AImageDecoder_createFromBuffer(const void* buffer, size_t length,
+                                   AImageDecoder** outDecoder) __INTRODUCED_IN(30);
+
+/**
+ * Delete the AImageDecoder.
+ */
+void AImageDecoder_delete(AImageDecoder* decoder) __INTRODUCED_IN(30);
+
+/**
+ * Choose the desired output format.
+ *
+ * @param format AndroidBitmapFormat to use
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} if the format is compatible
+ *         with the image and {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION}
+ *         otherwise. In the latter case, the AImageDecoder uses the
+ *         format it was already planning to use (either its default
+ *         or a previously successful setting from this function).
+ */
+int AImageDecoder_setAndroidBitmapFormat(AImageDecoder*,
+        int32_t format) __INTRODUCED_IN(30);
+
+/*
+ * Choose the desired output format.
+ *
+ * Must be one of:
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_UNPREMUL}
+ *
+ * Note: An OPAQUE image may be set to any of them.
+ *       A non-OPAQUE image may not be set to OPAQUE
+ *
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ *         - {@link ANDROID_IMAGE_DECODER_INVALID_CONVERSION} if the conversion
+ *           is not possible
+ *         - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} for bad parameters
+ */
+int AImageDecoder_setAlphaFlags(AImageDecoder*, int alphaFlags) __INTRODUCED_IN(30);
+
+/**
+ * Specify the output size for a decoded image.
+ *
+ * Future calls to {@link AImageDecoder_decodeImage} will sample or scale the
+ * encoded image to reach the desired size. If a crop rect is set (via
+ * {@link AImageDecoder_setCrop}), it must be contained within the dimensions
+ * specified by width and height, and the output image will be the size of the
+ * crop rect.
+ *
+ * @param width Width of the output (prior to cropping).
+ *              This will affect future calls to
+ *              {@link AImageDecoder_getMinimumStride}, which will now return
+ *              a value based on this width.
+ * @param height Height of the output (prior to cropping).
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ *         - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
+ *           pointer is null, width or height is <= 0, or any existing crop is
+ *           not contained by the image dimensions.
+ */
+int AImageDecoder_setTargetSize(AImageDecoder*, int width, int height) __INTRODUCED_IN(30);
+
+/**
+ * Specify how to crop the output after scaling (if any).
+ *
+ * Future calls to {@link AImageDecoder_decodeImage} will crop their output to
+ * the specified {@link ARect}. Clients will only need to allocate enough memory
+ * for the cropped ARect.
+ *
+ * @param crop Rectangle describing a crop of the decode. It must be contained inside of
+ *             the (possibly scaled, by {@link AImageDecoder_setTargetSize})
+ *             image dimensions. This will affect future calls to
+ *             {@link AImageDecoder_getMinimumStride}, which will now return a
+ *             value based on the width of the crop. An empty ARect -
+ *             specifically { 0, 0, 0, 0 } - may be used to remove the cropping
+ *             behavior. Any other empty or unsorted ARects will result in
+ *             returning ANDROID_IMAGE_DECODER_BAD_PARAMETER.
+ * @return - {@link ANDROID_IMAGE_DECODER_SUCCESS} on success
+ *         - {@link ANDROID_IMAGE_DECODER_BAD_PARAMETER} if the AImageDecoder
+ *           pointer is null or the crop is not contained by the image
+ *           dimensions.
+ */
+int AImageDecoder_setCrop(AImageDecoder*, ARect crop) __INTRODUCED_IN(30);
+
+/**
+ * Opaque handle for reading header info.
+ */
+struct AImageDecoderHeaderInfo;
+typedef struct AImageDecoderHeaderInfo AImageDecoderHeaderInfo;
+
+/**
+ * Return an opaque handle for reading header info.
+ *
+ * This is owned by the {@link AImageDecoder} and will be destroyed when the
+ * AImageDecoder is destroyed via {@link AImageDecoder_delete}.
+ */
+const AImageDecoderHeaderInfo* AImageDecoder_getHeaderInfo(
+        const AImageDecoder*) __INTRODUCED_IN(30);
+
+/**
+ * Report the native width of the encoded image.
+ */
+int32_t AImageDecoderHeaderInfo_getWidth(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report the native height of the encoded image.
+ */
+int32_t AImageDecoderHeaderInfo_getHeight(const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report the mimeType of the encoded image.
+ *
+ * @return a string literal describing the mime type.
+ */
+const char* AImageDecoderHeaderInfo_getMimeType(
+        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report whether the encoded image represents an animation.
+ */
+bool AImageDecoderHeaderInfo_isAnimated(
+        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report the AndroidBitmapFormat the AImageDecoder will decode to
+ * by default. AImageDecoder will try to choose one that is sensible
+ * for the image and the system. Note that this does not indicate the
+ * encoded format of the image.
+ */
+AndroidBitmapFormat AImageDecoderHeaderInfo_getAndroidBitmapFormat(
+        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Report how the AImageDecoder will handle alpha by default. If the image
+ * contains no alpha (according to its header), this will return
+ * {@link ANDROID_BITMAP_FLAGS_ALPHA_OPAQUE}. If the image may contain alpha,
+ * this returns {@link ANDROID_BITMAP_FLAGS_ALPHA_PREMUL}.
+ *
+ * For animated images only the opacity of the first frame is reported.
+ */
+int AImageDecoderHeaderInfo_getAlphaFlags(
+        const AImageDecoderHeaderInfo*) __INTRODUCED_IN(30);
+
+/**
+ * Return the minimum stride that can be used, taking the specified
+ * (or default) (possibly scaled) width, crop rect and
+ * {@link AndroidBitmapFormat} into account.
+ */
+size_t AImageDecoder_getMinimumStride(AImageDecoder*) __INTRODUCED_IN(30);
+
+/**
+ * Decode the image into pixels, using the settings of the AImageDecoder.
+ *
+ * @param decoder Opaque object representing the decoder.
+ * @param pixels On success, will be filled with the result
+ *               of the decode. Must be large enough to fit |size| bytes.
+ * @param stride Width in bytes of a single row. Must be at least
+ *               {@link AImageDecoder_getMinimumStride}.
+ * @param size Size of the pixel buffer in bytes. Must be at least
+ *             stride * (height - 1) +
+ *             {@link AImageDecoder_getMinimumStride}.
+ * @return {@link ANDROID_IMAGE_DECODER_SUCCESS} on success, or an error code
+ *         from the same enum describing the failure.
+ */
+int AImageDecoder_decodeImage(AImageDecoder* decoder,
+                              void* pixels, size_t stride,
+                              size_t size) __INTRODUCED_IN(30);
+
+#endif // __ANDROID_API__ >= 30
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // ANDROID_IMAGE_DECODER_H
+
+/** @} */
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index fa456bb..6100626 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -17,16 +17,23 @@
 #ifndef _LIBINPUT_DISPLAY_VIEWPORT_H
 #define _LIBINPUT_DISPLAY_VIEWPORT_H
 
-#include <android-base/stringprintf.h>
-#include <ui/DisplayInfo.h>
-#include <input/Input.h>
-#include <inttypes.h>
+#include <cinttypes>
 #include <optional>
 
+#include <android-base/stringprintf.h>
+#include <input/Input.h>
+
 using android::base::StringPrintf;
 
 namespace android {
 
+enum {
+    DISPLAY_ORIENTATION_0 = 0,
+    DISPLAY_ORIENTATION_90 = 1,
+    DISPLAY_ORIENTATION_180 = 2,
+    DISPLAY_ORIENTATION_270 = 3
+};
+
 /**
  * Describes the different type of viewports supported by input flinger.
  * Keep in sync with values in InputManagerService.java.
diff --git a/include/input/TouchVideoFrame.h b/include/input/TouchVideoFrame.h
index b49c623..4fa2f86 100644
--- a/include/input/TouchVideoFrame.h
+++ b/include/input/TouchVideoFrame.h
@@ -19,7 +19,6 @@
 
 #include <stdint.h>
 #include <sys/time.h>
-#include <ui/DisplayInfo.h>
 #include <vector>
 
 namespace android {
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
index a8f7d92..b1943a4 100644
--- a/libs/cputimeinstate/Android.bp
+++ b/libs/cputimeinstate/Android.bp
@@ -14,6 +14,7 @@
         "-Wall",
         "-Wextra",
     ],
+    export_include_dirs: ["."],
 }
 
 cc_test {
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
index 4ee9f55..ee44cf5 100644
--- a/libs/cputimeinstate/cputimeinstate.cpp
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -85,6 +85,16 @@
     return policyN1 - policyN2;
 }
 
+static int bpf_obj_get_wronly(const char *pathname) {
+    union bpf_attr attr;
+
+    memset(&attr, 0, sizeof(attr));
+    attr.pathname = ptr_to_u64((void *)pathname);
+    attr.file_flags = BPF_F_WRONLY;
+
+    return syscall(__NR_bpf, BPF_OBJ_GET, &attr, sizeof(attr));
+}
+
 static bool initGlobals() {
     std::lock_guard<std::mutex> guard(gInitializedMutex);
     if (gInitialized) return true;
@@ -153,17 +163,17 @@
 bool startTrackingUidTimes() {
     if (!initGlobals()) return false;
 
-    unique_fd fd(bpf_obj_get(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
-    if (fd < 0) return false;
+    unique_fd cpuPolicyFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_policy_map"));
+    if (cpuPolicyFd < 0) return false;
 
     for (uint32_t i = 0; i < gPolicyCpus.size(); ++i) {
         for (auto &cpu : gPolicyCpus[i]) {
-            if (writeToMapEntry(fd, &cpu, &i, BPF_ANY)) return false;
+            if (writeToMapEntry(cpuPolicyFd, &cpu, &i, BPF_ANY)) return false;
         }
     }
 
-    unique_fd fd2(bpf_obj_get(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
-    if (fd2 < 0) return false;
+    unique_fd freqToIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_freq_to_idx_map"));
+    if (freqToIdxFd < 0) return false;
     freq_idx_key_t key;
     for (uint32_t i = 0; i < gNPolicies; ++i) {
         key.policy = i;
@@ -173,14 +183,41 @@
             // The uid_times map still uses 0-based indexes, and the sched_switch program handles
             // conversion between them, so this does not affect our map reading code.
             uint32_t idx = j + 1;
-            if (writeToMapEntry(fd2, &key, &idx, BPF_ANY)) return false;
+            if (writeToMapEntry(freqToIdxFd, &key, &idx, BPF_ANY)) return false;
         }
     }
 
+    unique_fd cpuLastUpdateFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_cpu_last_update_map"));
+    if (cpuLastUpdateFd < 0) return false;
+    std::vector<uint64_t> zeros(get_nprocs_conf(), 0);
+    uint32_t zero = 0;
+    if (writeToMapEntry(cpuLastUpdateFd, &zero, zeros.data(), BPF_ANY)) return false;
+
+    unique_fd nrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_nr_active_map"));
+    if (nrActiveFd < 0) return false;
+    if (writeToMapEntry(nrActiveFd, &zero, &zero, BPF_ANY)) return false;
+
+    unique_fd policyNrActiveFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_nr_active_map"));
+    if (policyNrActiveFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyNrActiveFd, &i, &zero, BPF_ANY)) return false;
+    }
+
+    unique_fd policyFreqIdxFd(bpf_obj_get_wronly(BPF_FS_PATH "map_time_in_state_policy_freq_idx_map"));
+    if (policyFreqIdxFd < 0) return false;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        if (writeToMapEntry(policyFreqIdxFd, &i, &zero, BPF_ANY)) return false;
+    }
+
     return attachTracepointProgram("sched", "sched_switch") &&
             attachTracepointProgram("power", "cpu_frequency");
 }
 
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs() {
+    if (!gInitialized && !initGlobals()) return {};
+    return gPolicyFreqs;
+}
+
 // Retrieve the times in ns that uid spent running at each CPU frequency.
 // Return contains no value on error, otherwise it contains a vector of vectors using the format:
 // [[t0_0, t0_1, ...],
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
index f620715..49469d8 100644
--- a/libs/cputimeinstate/cputimeinstate.h
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -26,6 +26,7 @@
 std::optional<std::vector<std::vector<uint64_t>>> getUidCpuFreqTimes(uint32_t uid);
 std::optional<std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>>>
     getUidsCpuFreqTimes();
+std::optional<std::vector<std::vector<uint32_t>>> getCpuFreqs();
 
 struct concurrent_time_t {
     std::vector<uint64_t> active;
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
index c0cd3e0..23d87fd 100644
--- a/libs/cputimeinstate/testtimeinstate.cpp
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -1,3 +1,19 @@
+/*
+ * 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 <bpf_timeinstate.h>
 
@@ -351,5 +367,16 @@
     ASSERT_EQ(allConcurrentTimes->find(uid), allConcurrentTimes->end());
 }
 
+TEST(TimeInStateTest, GetCpuFreqs) {
+    auto freqs = getCpuFreqs();
+    ASSERT_TRUE(freqs.has_value());
+
+    auto times = getUidCpuFreqTimes(0);
+    ASSERT_TRUE(times.has_value());
+
+    ASSERT_EQ(freqs->size(), times->size());
+    for (size_t i = 0; i < freqs->size(); ++i) EXPECT_EQ((*freqs)[i].size(), (*times)[i].size());
+}
+
 } // namespace bpf
 } // namespace android
diff --git a/libs/dumputils/dump_utils.cpp b/libs/dumputils/dump_utils.cpp
index 0477801..875059c 100644
--- a/libs/dumputils/dump_utils.cpp
+++ b/libs/dumputils/dump_utils.cpp
@@ -34,7 +34,6 @@
         "/system/bin/mediametrics", // media.metrics
         "/system/bin/mediaserver",
         "/system/bin/netd",
-        "/system/bin/vold",
         "/system/bin/sdcard",
         "/system/bin/statsd",
         "/system/bin/surfaceflinger",
@@ -44,6 +43,13 @@
         NULL,
 };
 
+
+// Native processes to dump on debuggable builds.
+static const char* debuggable_native_processes_to_dump[] = {
+        "/system/bin/vold",
+        NULL,
+};
+
 /* list of hal interface to dump containing process during native dumps */
 static const char* hal_interfaces_to_dump[] {
         "android.hardware.audio@2.0::IDevicesFactory",
@@ -106,6 +112,15 @@
             return true;
         }
     }
+
+    if (android::base::GetBoolProperty("ro.debuggable", false)) {
+        for (const char** p = debuggable_native_processes_to_dump; *p; p++) {
+            if (!strcmp(*p, path)) {
+                return true;
+            }
+        }
+    }
+
     return false;
 }
 
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index f07c231..befabee 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -611,6 +611,10 @@
     return mDriverNamespace;
 }
 
+std::string GraphicsEnv::getDriverPath() const {
+    return mDriverPath;
+}
+
 android_namespace_t* GraphicsEnv::getAngleNamespace() {
     std::lock_guard<std::mutex> lock(mNamespaceMutex);
 
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 2219074..22a2332 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -58,6 +58,7 @@
     void setDriverPathAndSphalLibraries(const std::string path, const std::string sphalLibraries);
     // Get the updatable driver namespace.
     android_namespace_t* getDriverNamespace();
+    std::string getDriverPath() const;
 
     /*
      * Apis for GpuStats
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index a5e5693..f88ddf1 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -37,8 +37,6 @@
         mHeight(height),
         mNextTransaction(nullptr) {
     BufferQueue::createBufferQueue(&mProducer, &mConsumer);
-    mConsumer->setMaxBufferCount(MAX_BUFFERS);
-    mProducer->setMaxDequeuedBufferCount(MAX_BUFFERS - 1);
     mConsumer->setMaxAcquiredBufferCount(MAX_ACQUIRED_BUFFERS);
     mBufferItemConsumer =
             new BufferItemConsumer(mConsumer, AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER, 1, true);
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index ab4d51e..d34fe3b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -110,10 +110,10 @@
     }
 
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
-                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   bool& outCapturedSecureLayers, ui::Dataspace reqDataspace,
+                                   ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   ISurfaceComposer::Rotation rotation, bool captureSecureLayers) {
+                                   ui::Rotation rotation, bool captureSecureLayers) {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeStrongBinder(display);
@@ -1214,8 +1214,7 @@
             bool capturedSecureLayers = false;
             status_t res = captureScreen(display, &outBuffer, capturedSecureLayers, reqDataspace,
                                          reqPixelFormat, sourceCrop, reqWidth, reqHeight,
-                                         useIdentityTransform,
-                                         static_cast<ISurfaceComposer::Rotation>(rotation),
+                                         useIdentityTransform, ui::toRotation(rotation),
                                          captureSecureLayers);
 
             reply->writeInt32(res);
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index e033f93..a7c4f46 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -203,7 +203,6 @@
 DisplayState::DisplayState() :
     what(0),
     layerStack(0),
-    orientation(eOrientationDefault),
     viewport(Rect::EMPTY_RECT),
     frame(Rect::EMPTY_RECT),
     width(0),
@@ -215,7 +214,7 @@
     output.writeStrongBinder(IInterface::asBinder(surface));
     output.writeUint32(what);
     output.writeUint32(layerStack);
-    output.writeUint32(orientation);
+    output.writeUint32(toRotationInt(orientation));
     output.write(viewport);
     output.write(frame);
     output.writeUint32(width);
@@ -228,7 +227,7 @@
     surface = interface_cast<IGraphicBufferProducer>(input.readStrongBinder());
     what = input.readUint32();
     layerStack = input.readUint32();
-    orientation = input.readUint32();
+    orientation = ui::toRotation(input.readUint32());
     input.read(viewport);
     input.read(frame);
     width = input.readUint32();
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index f378fc5..5e259e2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -225,9 +225,11 @@
                                               .surfaceControls[surfaceStats.surfaceControl],
                                       surfaceStats.acquireTime, surfaceStats.previousReleaseFence,
                                       surfaceStats.transformHint);
-                callbacksMap[callbackId]
-                        .surfaceControls[surfaceStats.surfaceControl]
-                        ->setTransformHint(surfaceStats.transformHint);
+                if (callbacksMap[callbackId].surfaceControls[surfaceStats.surfaceControl]) {
+                    callbacksMap[callbackId]
+                            .surfaceControls[surfaceStats.surfaceControl]
+                            ->setTransformHint(surfaceStats.transformHint);
+                }
             }
 
             callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
@@ -1399,9 +1401,9 @@
 }
 
 void SurfaceComposerClient::Transaction::setDisplayProjection(const sp<IBinder>& token,
-        uint32_t orientation,
-        const Rect& layerStackRect,
-        const Rect& displayRect) {
+                                                              ui::Rotation orientation,
+                                                              const Rect& layerStackRect,
+                                                              const Rect& displayRect) {
     DisplayState& s(getDisplayState(token));
     s.orientation = orientation;
     s.viewport = layerStackRect;
@@ -1773,28 +1775,26 @@
 
 // ----------------------------------------------------------------------------
 
-status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
-                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+status_t ScreenshotClient::capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+                                   ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   uint32_t rotation, bool captureSecureLayers,
+                                   ui::Rotation rotation, bool captureSecureLayers,
                                    sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
-    status_t ret =
-            s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace,
-                             reqPixelFormat, sourceCrop, reqWidth, reqHeight, useIdentityTransform,
-                             static_cast<ISurfaceComposer::Rotation>(rotation),
-                             captureSecureLayers);
+    status_t ret = s->captureScreen(display, outBuffer, outCapturedSecureLayers, reqDataSpace,
+                                    reqPixelFormat, sourceCrop, reqWidth, reqHeight,
+                                    useIdentityTransform, rotation, captureSecureLayers);
     if (ret != NO_ERROR) {
         return ret;
     }
     return ret;
 }
 
-status_t ScreenshotClient::capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
-                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+status_t ScreenshotClient::capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+                                   ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   uint32_t rotation, sp<GraphicBuffer>* outBuffer) {
+                                   ui::Rotation rotation, sp<GraphicBuffer>* outBuffer) {
     bool ignored;
     return capture(display, reqDataSpace, reqPixelFormat, sourceCrop, reqWidth, reqHeight,
                    useIdentityTransform, rotation, false, outBuffer, ignored);
@@ -1807,9 +1807,8 @@
     return s->captureScreen(displayOrLayerStack, outDataspace, outBuffer);
 }
 
-status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle,
-                                         const ui::Dataspace reqDataSpace,
-                                         const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace,
+                                         ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                          float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
     if (s == nullptr) return NO_INIT;
@@ -1819,8 +1818,8 @@
 }
 
 status_t ScreenshotClient::captureChildLayers(
-        const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
-        const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+        const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace, ui::PixelFormat reqPixelFormat,
+        const Rect& sourceCrop,
         const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>& excludeHandles,
         float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
@@ -1830,5 +1829,5 @@
                              excludeHandles, frameScale, true /* childrenOnly */);
     return ret;
 }
-// ----------------------------------------------------------------------------
-}; // namespace android
+
+} // namespace android
diff --git a/libs/gui/include/gui/BLASTBufferQueue.h b/libs/gui/include/gui/BLASTBufferQueue.h
index 0a0a03c..be429fe 100644
--- a/libs/gui/include/gui/BLASTBufferQueue.h
+++ b/libs/gui/include/gui/BLASTBufferQueue.h
@@ -69,7 +69,6 @@
     std::mutex mMutex;
     std::condition_variable mCallbackCV;
 
-    static const int MAX_BUFFERS = 3;
     static const int MAX_ACQUIRED_BUFFERS = 2;
 
     int32_t mNumFrameAvailable GUARDED_BY(mMutex);
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 998973c..9804c92 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -34,6 +34,7 @@
 #include <ui/GraphicTypes.h>
 #include <ui/PhysicalDisplayId.h>
 #include <ui/PixelFormat.h>
+#include <ui/Rotation.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
@@ -81,13 +82,6 @@
         eEarlyWakeup = 0x04
     };
 
-    enum Rotation {
-        eRotateNone = 0,
-        eRotate90   = 1,
-        eRotate180  = 2,
-        eRotate270  = 3
-    };
-
     enum VsyncSource {
         eVsyncSourceApp = 0,
         eVsyncSourceSurfaceFlinger = 1
@@ -249,10 +243,10 @@
      * it) around its center.
      */
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
-                                   const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+                                   bool& outCapturedSecureLayers, ui::Dataspace reqDataspace,
+                                   ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                    uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                                   Rotation rotation = eRotateNone,
+                                   ui::Rotation rotation = ui::ROTATION_0,
                                    bool captureSecureLayers = false) = 0;
     /**
      * Capture the specified screen. This requires READ_FRAME_BUFFER
@@ -276,8 +270,9 @@
      * it) around its center.
      */
     virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                   Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                                   bool useIdentityTransform, Rotation rotation = eRotateNone) {
+                                   const Rect& sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
+                                   bool useIdentityTransform,
+                                   ui::Rotation rotation = ui::ROTATION_0) {
         bool outIgnored;
         return captureScreen(display, outBuffer, outIgnored, ui::Dataspace::V0_SRGB,
                              ui::PixelFormat::RGBA_8888, sourceCrop, reqWidth, reqHeight,
@@ -301,8 +296,7 @@
      */
     virtual status_t captureLayers(
             const sp<IBinder>& layerHandleBinder, sp<GraphicBuffer>* outBuffer,
-            const ui::Dataspace reqDataspace, const ui::PixelFormat reqPixelFormat,
-            const Rect& sourceCrop,
+            ui::Dataspace reqDataspace, ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
             const std::unordered_set<sp<IBinder>, SpHash<IBinder>>& excludeHandles,
             float frameScale = 1.0, bool childrenOnly = false) = 0;
 
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index c2b5119..fb18639 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -35,6 +35,7 @@
 #include <ui/GraphicTypes.h>
 #include <ui/Rect.h>
 #include <ui/Region.h>
+#include <ui/Rotation.h>
 
 namespace android {
 
@@ -218,15 +219,6 @@
 
 struct DisplayState {
     enum {
-        eOrientationDefault = 0,
-        eOrientation90 = 1,
-        eOrientation180 = 2,
-        eOrientation270 = 3,
-        eOrientationUnchanged = 4,
-        eOrientationSwapMask = 0x01
-    };
-
-    enum {
         eSurfaceChanged = 0x01,
         eLayerStackChanged = 0x02,
         eDisplayProjectionChanged = 0x04,
@@ -252,7 +244,7 @@
     // 0, layers will be scaled by a factor of 2 and translated by (20, 10).
     // When orientation is 1, layers will be additionally rotated by 90
     // degrees around the origin clockwise and translated by (W, 0).
-    uint32_t orientation;
+    ui::Rotation orientation = ui::ROTATION_0;
     Rect viewport;
     Rect frame;
 
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 86468a4..44f29ea 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -35,6 +35,7 @@
 #include <ui/FrameStats.h>
 #include <ui/GraphicTypes.h>
 #include <ui/PixelFormat.h>
+#include <ui/Rotation.h>
 
 #include <gui/CpuConsumer.h>
 #include <gui/ISurfaceComposer.h>
@@ -531,10 +532,8 @@
          * mapped to. displayRect is specified post-orientation, that is
          * it uses the orientation seen by the end-user.
          */
-        void setDisplayProjection(const sp<IBinder>& token,
-                uint32_t orientation,
-                const Rect& layerStackRect,
-                const Rect& displayRect);
+        void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
+                                  const Rect& layerStackRect, const Rect& displayRect);
         void setDisplaySize(const sp<IBinder>& token, uint32_t width, uint32_t height);
         void setAnimationTransaction();
         void setEarlyWakeup();
@@ -548,10 +547,8 @@
     static status_t getHdrCapabilities(const sp<IBinder>& display,
             HdrCapabilities* outCapabilities);
 
-    static void setDisplayProjection(const sp<IBinder>& token,
-            uint32_t orientation,
-            const Rect& layerStackRect,
-            const Rect& displayRect);
+    static void setDisplayProjection(const sp<IBinder>& token, ui::Rotation orientation,
+                                     const Rect& layerStackRect, const Rect& displayRect);
 
     inline sp<ISurfaceComposerClient> getClient() { return mClient; }
 
@@ -583,23 +580,23 @@
 public:
     // if cropping isn't required, callers may pass in a default Rect, e.g.:
     //   capture(display, producer, Rect(), reqWidth, ...);
-    static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
-                            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+    static status_t capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+                            ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                             uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                            uint32_t rotation, bool captureSecureLayers,
+                            ui::Rotation rotation, bool captureSecureLayers,
                             sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers);
-    static status_t capture(const sp<IBinder>& display, const ui::Dataspace reqDataSpace,
-                            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+    static status_t capture(const sp<IBinder>& display, ui::Dataspace reqDataSpace,
+                            ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                             uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
-                            uint32_t rotation, sp<GraphicBuffer>* outBuffer);
+                            ui::Rotation rotation, sp<GraphicBuffer>* outBuffer);
     static status_t capture(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
                             sp<GraphicBuffer>* outBuffer);
-    static status_t captureLayers(const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
-                                  const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+    static status_t captureLayers(const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace,
+                                  ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
                                   float frameScale, sp<GraphicBuffer>* outBuffer);
     static status_t captureChildLayers(
-            const sp<IBinder>& layerHandle, const ui::Dataspace reqDataSpace,
-            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
+            const sp<IBinder>& layerHandle, ui::Dataspace reqDataSpace,
+            ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
             const std::unordered_set<sp<IBinder>, ISurfaceComposer::SpHash<IBinder>>&
                     excludeHandles,
             float frameScale, sp<GraphicBuffer>* outBuffer);
diff --git a/libs/gui/tests/BLASTBufferQueue_test.cpp b/libs/gui/tests/BLASTBufferQueue_test.cpp
index 0f618f1..8fca883 100644
--- a/libs/gui/tests/BLASTBufferQueue_test.cpp
+++ b/libs/gui/tests/BLASTBufferQueue_test.cpp
@@ -123,11 +123,12 @@
     void setUpProducer(BLASTBufferQueueHelper adapter, sp<IGraphicBufferProducer>& producer) {
         auto igbProducer = adapter.getIGraphicBufferProducer();
         ASSERT_NE(nullptr, igbProducer.get());
+        ASSERT_EQ(NO_ERROR, igbProducer->setMaxDequeuedBufferCount(2));
         IGraphicBufferProducer::QueueBufferOutput qbOutput;
         ASSERT_EQ(NO_ERROR,
                   igbProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
                                        &qbOutput));
-        ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+        ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
         producer = igbProducer;
     }
 
@@ -266,7 +267,7 @@
                                                    NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
                                                    Fence::NO_FENCE);
     igbProducer->queueBuffer(slot, input, &qbOutput);
-    ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+    ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
 
     adapter.waitForCallbacks();
 
@@ -349,7 +350,7 @@
                                                    NATIVE_WINDOW_SCALING_MODE_FREEZE, 0,
                                                    Fence::NO_FENCE);
     igbProducer->queueBuffer(slot, input, &qbOutput);
-    ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+    ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
 
     adapter.waitForCallbacks();
     // capture screen and verify that it is red
@@ -410,7 +411,7 @@
                                                    NATIVE_WINDOW_SCALING_MODE_SCALE_CROP, 0,
                                                    Fence::NO_FENCE);
     igbProducer->queueBuffer(slot, input, &qbOutput);
-    ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+    ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
 
     adapter.waitForCallbacks();
     // capture screen and verify that it is red
@@ -456,7 +457,7 @@
                                                        NATIVE_WINDOW_SCALING_MODE_FREEZE, tr,
                                                        Fence::NO_FENCE);
         igbProducer->queueBuffer(slot, input, &qbOutput);
-        ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, qbOutput.transformHint);
+        ASSERT_NE(ui::Transform::ROT_INVALID, qbOutput.transformHint);
 
         adapter.waitForCallbacks();
         bool capturedSecureLayers;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 0445755..f9540b2 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -742,11 +742,10 @@
     status_t setActiveColorMode(const sp<IBinder>& /*display*/,
         ColorMode /*colorMode*/) override { return NO_ERROR; }
     status_t captureScreen(const sp<IBinder>& /*display*/, sp<GraphicBuffer>* /*outBuffer*/,
-                           bool& /* outCapturedSecureLayers */,
-                           const ui::Dataspace /*reqDataspace*/,
-                           const ui::PixelFormat /*reqPixelFormat*/, Rect /*sourceCrop*/,
+                           bool& /*outCapturedSecureLayers*/, ui::Dataspace /*reqDataspace*/,
+                           ui::PixelFormat /*reqPixelFormat*/, const Rect& /*sourceCrop*/,
                            uint32_t /*reqWidth*/, uint32_t /*reqHeight*/,
-                           bool /*useIdentityTransform*/, Rotation /*rotation*/,
+                           bool /*useIdentityTransform*/, ui::Rotation,
                            bool /*captureSecureLayers*/) override {
         return NO_ERROR;
     }
@@ -766,7 +765,7 @@
     }
     virtual status_t captureLayers(
             const sp<IBinder>& /*parentHandle*/, sp<GraphicBuffer>* /*outBuffer*/,
-            const ui::Dataspace /*reqDataspace*/, const ui::PixelFormat /*reqPixelFormat*/,
+            ui::Dataspace /*reqDataspace*/, ui::PixelFormat /*reqPixelFormat*/,
             const Rect& /*sourceCrop*/,
             const std::unordered_set<sp<IBinder>,
                                      ISurfaceComposer::SpHash<IBinder>>& /*excludeHandles*/,
diff --git a/libs/input/TouchVideoFrame.cpp b/libs/input/TouchVideoFrame.cpp
index 8a4298a..145b4ae 100644
--- a/libs/input/TouchVideoFrame.cpp
+++ b/libs/input/TouchVideoFrame.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <input/DisplayViewport.h>
 #include <input/TouchVideoFrame.h>
 
 namespace android {
diff --git a/libs/input/tests/TouchVideoFrame_test.cpp b/libs/input/tests/TouchVideoFrame_test.cpp
index 815424e..1ec9358 100644
--- a/libs/input/tests/TouchVideoFrame_test.cpp
+++ b/libs/input/tests/TouchVideoFrame_test.cpp
@@ -16,6 +16,7 @@
 
 #include <gtest/gtest.h>
 
+#include <input/DisplayViewport.h>
 #include <input/TouchVideoFrame.h>
 
 namespace android {
diff --git a/libs/ui/include/ui/DisplayInfo.h b/libs/ui/include/ui/DisplayInfo.h
index 0772210..38f8d6b 100644
--- a/libs/ui/include/ui/DisplayInfo.h
+++ b/libs/ui/include/ui/DisplayInfo.h
@@ -20,6 +20,7 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <ui/Rotation.h>
 #include <utils/Timers.h>
 
 namespace android {
@@ -33,7 +34,7 @@
     float ydpi{0};
     float fps{0};
     float density{0};
-    uint8_t orientation{0};
+    ui::Rotation orientation{ui::ROTATION_0};
     bool secure{false};
     nsecs_t appVsyncOffset{0};
     nsecs_t presentationDeadline{0};
@@ -42,14 +43,6 @@
     uint32_t layerStack{NO_LAYER_STACK};
 };
 
-/* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
-enum {
-    DISPLAY_ORIENTATION_0 = 0,
-    DISPLAY_ORIENTATION_90 = 1,
-    DISPLAY_ORIENTATION_180 = 2,
-    DISPLAY_ORIENTATION_270 = 3
-};
-
 } // namespace android
 
 #endif // ANDROID_COMPOSER_DISPLAY_INFO_H
diff --git a/libs/ui/include/ui/Rotation.h b/libs/ui/include/ui/Rotation.h
new file mode 100644
index 0000000..89008f6
--- /dev/null
+++ b/libs/ui/include/ui/Rotation.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <type_traits>
+
+namespace android::ui {
+
+enum class Rotation { Rotation0 = 0, Rotation90 = 1, Rotation180 = 2, Rotation270 = 3 };
+
+// Equivalent to Surface.java constants.
+constexpr auto ROTATION_0 = Rotation::Rotation0;
+constexpr auto ROTATION_90 = Rotation::Rotation90;
+constexpr auto ROTATION_180 = Rotation::Rotation180;
+constexpr auto ROTATION_270 = Rotation::Rotation270;
+
+constexpr auto toRotation(std::underlying_type_t<Rotation> rotation) {
+    return static_cast<Rotation>(rotation);
+}
+
+constexpr auto toRotationInt(Rotation rotation) {
+    return static_cast<std::underlying_type_t<Rotation>>(rotation);
+}
+
+constexpr Rotation operator+(Rotation lhs, Rotation rhs) {
+    constexpr auto N = toRotationInt(ROTATION_270) + 1;
+    return toRotation((toRotationInt(lhs) + toRotationInt(rhs)) % N);
+}
+
+constexpr const char* toCString(Rotation rotation) {
+    switch (rotation) {
+        case ROTATION_0:
+            return "ROTATION_0";
+        case ROTATION_90:
+            return "ROTATION_90";
+        case ROTATION_180:
+            return "ROTATION_180";
+        case ROTATION_270:
+            return "ROTATION_270";
+    }
+}
+
+} // namespace android::ui
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index de07684..c6bb598 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_TRANSFORM_H
-#define ANDROID_TRANSFORM_H
+#pragma once
 
 #include <stdint.h>
 #include <sys/types.h>
@@ -28,6 +27,7 @@
 #include <math/vec3.h>
 #include <ui/Point.h>
 #include <ui/Rect.h>
+#include <ui/Rotation.h>
 
 namespace android {
 
@@ -42,13 +42,13 @@
     explicit Transform(uint32_t orientation, int w = 0, int h = 0);
     ~Transform();
 
-    enum orientation_flags {
-        ROT_0   = 0x00000000,
-        FLIP_H  = HAL_TRANSFORM_FLIP_H,
-        FLIP_V  = HAL_TRANSFORM_FLIP_V,
-        ROT_90  = HAL_TRANSFORM_ROT_90,
-        ROT_180 = FLIP_H|FLIP_V,
-        ROT_270 = ROT_180|ROT_90,
+    enum RotationFlags : uint32_t {
+        ROT_0 = 0,
+        FLIP_H = HAL_TRANSFORM_FLIP_H,
+        FLIP_V = HAL_TRANSFORM_FLIP_V,
+        ROT_90 = HAL_TRANSFORM_ROT_90,
+        ROT_180 = FLIP_H | FLIP_V,
+        ROT_270 = ROT_180 | ROT_90,
         ROT_INVALID = 0x80
     };
 
@@ -100,6 +100,8 @@
     void dump(std::string& result, const char* name) const;
     void dump(const char* name) const;
 
+    static RotationFlags toRotationFlags(Rotation);
+
 private:
     struct mat33 {
         vec3 v[3];
@@ -117,13 +119,26 @@
     mutable uint32_t    mType;
 };
 
-static inline void PrintTo(const Transform& t, ::std::ostream* os) {
+inline void PrintTo(const Transform& t, ::std::ostream* os) {
     std::string out;
     t.dump(out, "ui::Transform");
     *os << out;
 }
 
+inline Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) {
+    switch (rotation) {
+        case ROTATION_0:
+            return ROT_0;
+        case ROTATION_90:
+            return ROT_90;
+        case ROTATION_180:
+            return ROT_180;
+        case ROTATION_270:
+            return ROT_270;
+        default:
+            return ROT_INVALID;
+    }
+}
+
 }  // namespace ui
 }  // namespace android
-
-#endif /* ANDROID_TRANSFORM_H */
diff --git a/libs/ui/include_vndk/ui/Rotation.h b/libs/ui/include_vndk/ui/Rotation.h
new file mode 120000
index 0000000..d84fb4b
--- /dev/null
+++ b/libs/ui/include_vndk/ui/Rotation.h
@@ -0,0 +1 @@
+../../include/ui/Rotation.h
\ No newline at end of file
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 188ac6b..b771538 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1215,6 +1215,12 @@
   return Void();
 }
 
+Return<void> HardwareComposer::ComposerCallback::onSeamlessPossible(
+    Hwc2::Display /*display*/) {
+  LOG_ALWAYS_FATAL("Unexpected onSeamlessPossible callback");
+  return Void();
+}
+
 void HardwareComposer::ComposerCallback::SetVsyncService(
     const sp<VsyncService>& vsync_service) {
   std::lock_guard<std::mutex> lock(mutex_);
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 8698814..bfce10b 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -381,6 +381,7 @@
     hardware::Return<void> onVsyncPeriodTimingChanged(
         Hwc2::Display display,
         const Hwc2::VsyncPeriodChangeTimeline& updatedTimeline) override;
+    hardware::Return<void> onSeamlessPossible(Hwc2::Display display) override;
 
     bool GotFirstHotplug() { return got_first_hotplug_; }
     void SetVsyncService(const sp<VsyncService>& vsync_service);
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index e143260..51878e9 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -25,7 +25,6 @@
 #include <dlfcn.h>
 
 #include <android/dlext.h>
-#include <cutils/properties.h>
 #include <log/log.h>
 #include <utils/Timers.h>
 
@@ -206,6 +205,7 @@
     }
 
     cnx->systemDriverUnloaded = true;
+    cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
 }
 
 void* Loader::open(egl_connection_t* cnx)
@@ -228,6 +228,7 @@
     } else {
         cnx->shouldUseAngle = false;
     }
+    cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
 
     // Firstly, try to load ANGLE driver.
     driver_t* hnd = attempt_to_load_angle(cnx);
@@ -237,22 +238,31 @@
     }
 
     bool failToLoadFromDriverSuffixProperty = false;
+    cnx->systemDriverUseExactName = true;
     if (!hnd) {
+        // If updated driver apk is set but fail to load, abort here.
+        if (android::GraphicsEnv::getInstance().getDriverNamespace()) {
+            LOG_ALWAYS_FATAL("couldn't find an OpenGL ES implementation from %s",
+                             android::GraphicsEnv::getInstance().getDriverPath().c_str());
+        }
         // Finally, try to load system driver, start by searching for the library name appended by
         // the system properties of the GLES userspace driver in both locations.
         // i.e.:
         //      libGLES_${prop}.so, or:
         //      libEGL_${prop}.so, libGLESv1_CM_${prop}.so, libGLESv2_${prop}.so
-        char prop[PROPERTY_VALUE_MAX + 1];
         for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
-            if (property_get(key, prop, nullptr) <= 0) {
+            if (property_get(key, cnx->systemDriverProperty, nullptr) <= 0) {
                 continue;
             }
-            hnd = attempt_to_load_system_driver(cnx, prop, true);
+            hnd = attempt_to_load_system_driver(cnx, cnx->systemDriverProperty,
+                                                cnx->systemDriverUseExactName);
             if (hnd) {
+                cnx->systemDriverUseProperty = true;
                 break;
-            } else if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
-                failToLoadFromDriverSuffixProperty = true;
+            } else {
+                if (strcmp(key, DRIVER_SUFFIX_PROPERTY) == 0) {
+                    failToLoadFromDriverSuffixProperty = true;
+                }
             }
         }
     }
@@ -263,11 +273,12 @@
         // i.e.:
         //      libGLES.so, or:
         //      libEGL.so, libGLESv1_CM.so, libGLESv2.so
-        hnd = attempt_to_load_system_driver(cnx, nullptr, true);
+        hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
     }
 
     if (!hnd && !failToLoadFromDriverSuffixProperty) {
-        hnd = attempt_to_load_system_driver(cnx, nullptr, false);
+        cnx->systemDriverUseExactName = false;
+        hnd = attempt_to_load_system_driver(cnx, nullptr, cnx->systemDriverUseExactName);
     }
 
     if (!hnd) {
@@ -282,14 +293,11 @@
     if (!cnx->libEgl) {
         cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
     }
-    if (!cnx->libGles1) {
-        cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
-    }
     if (!cnx->libGles2) {
         cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
     }
 
-    if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
+    if (!cnx->libEgl || !cnx->libGles2) {
         android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL,
                                                             false, systemTime() - openTime);
     }
@@ -297,8 +305,7 @@
     LOG_ALWAYS_FATAL_IF(!cnx->libEgl,
             "couldn't load system EGL wrapper libraries");
 
-    LOG_ALWAYS_FATAL_IF(!cnx->libGles2 || !cnx->libGles1,
-            "couldn't load system OpenGL ES wrapper libraries");
+    LOG_ALWAYS_FATAL_IF(!cnx->libGles2, "couldn't load system OpenGL ESv2+ wrapper libraries");
 
     android::GraphicsEnv::getInstance().setDriverLoaded(android::GpuStatsInfo::Api::API_GL, true,
                                                         systemTime() - openTime);
@@ -314,7 +321,7 @@
 
     cnx->shouldUseAngle = false;
     cnx->angleDecided = false;
-    cnx->useAngle = false;
+    cnx->loadedDriverType = egl_connection_t::GLES_NO_DRIVER;
 
     if (cnx->vendorEGL) {
         dlclose(cnx->vendorEGL);
@@ -519,7 +526,6 @@
     if (so) {
         ALOGV("Loaded ANGLE %s library for '%s' (instead of native)", kind,
             android::GraphicsEnv::getInstance().getAngleAppName().c_str());
-        cnx->useAngle = true;
 
         char prop[PROPERTY_VALUE_MAX];
 
@@ -562,7 +568,6 @@
     } else {
         ALOGV("Loaded native %s library for '%s' (instead of ANGLE)", kind,
             android::GraphicsEnv::getInstance().getAngleAppName().c_str());
-        cnx->useAngle = false;
     }
     cnx->angleDecided = true;
 
@@ -592,6 +597,7 @@
 
 Loader::driver_t* Loader::attempt_to_load_angle(egl_connection_t* cnx) {
     ATRACE_CALL();
+    assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
     if (!ns) {
         return nullptr;
@@ -606,19 +612,17 @@
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
-        dso = load_angle("GLESv1_CM", ns, cnx);
-        initialize_api(dso, cnx, GLESv1_CM);
-        hnd->set(dso, GLESv1_CM);
-
         dso = load_angle("GLESv2", ns, cnx);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
+        cnx->loadedDriverType = egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER;
     }
     return hnd;
 }
 
 Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx) {
     ATRACE_CALL();
+    assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
 #ifndef __ANDROID_VNDK__
     android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
     if (!ns) {
@@ -630,8 +634,9 @@
     driver_t* hnd = nullptr;
     void* dso = load_updated_driver("GLES", ns);
     if (dso) {
-        initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
+        initialize_api(dso, cnx, EGL | GLESv2);
         hnd = new driver_t(dso);
+        if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_COMBO_DRIVER;
         return hnd;
     }
 
@@ -640,13 +645,10 @@
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
-        dso = load_updated_driver("GLESv1_CM", ns);
-        initialize_api(dso, cnx, GLESv1_CM);
-        hnd->set(dso, GLESv1_CM);
-
         dso = load_updated_driver("GLESv2", ns);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
+        cnx->loadedDriverType = egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER;
     }
     return hnd;
 #else
@@ -657,30 +659,94 @@
 Loader::driver_t* Loader::attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix,
                                                         const bool exact) {
     ATRACE_CALL();
+    assert(cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER);
     android::GraphicsEnv::getInstance().setDriverToLoad(android::GpuStatsInfo::Driver::GL);
     driver_t* hnd = nullptr;
     void* dso = load_system_driver("GLES", suffix, exact);
     if (dso) {
-        initialize_api(dso, cnx, EGL | GLESv1_CM | GLESv2);
+        initialize_api(dso, cnx, EGL | GLESv2);
         hnd = new driver_t(dso);
+        if (hnd) cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_COMBO_DRIVER;
         return hnd;
     }
+
     dso = load_system_driver("EGL", suffix, exact);
     if (dso) {
         initialize_api(dso, cnx, EGL);
         hnd = new driver_t(dso);
 
-        dso = load_system_driver("GLESv1_CM", suffix, exact);
-        initialize_api(dso, cnx, GLESv1_CM);
-        hnd->set(dso, GLESv1_CM);
-
         dso = load_system_driver("GLESv2", suffix, exact);
         initialize_api(dso, cnx, GLESv2);
         hnd->set(dso, GLESv2);
+        cnx->loadedDriverType = egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER;
     }
     return hnd;
 }
 
+bool Loader::load_glesv1_driver(egl_connection_t* cnx) {
+    ATRACE_CALL();
+    void* dso = nullptr;
+
+    driver_t* hnd = (driver_t*)cnx->dso;
+    // EGL driver must have been loaded. if not, something went wrong.
+    if (!hnd || cnx->loadedDriverType == egl_connection_t::GLES_NO_DRIVER) {
+        return false;
+    }
+
+    if (cnx->libGles1) return EGL_TRUE;
+
+    // If there is a GLES driver, use that first
+    switch (cnx->loadedDriverType) {
+        case egl_connection_t::GLES_SYSTEM_COMBO_DRIVER:
+        case egl_connection_t::GLES_UPDATED_COMBO_DRIVER: {
+            dso = hnd->dso[0];
+            initialize_api(dso, cnx, GLESv1_CM);
+            break;
+        }
+        case egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER: {
+            android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
+            dso = load_angle("GLESv1_CM", ns, cnx);
+            if (dso) {
+                initialize_api(dso, cnx, GLESv1_CM);
+                hnd->set(dso, GLESv1_CM);
+            }
+            break;
+        }
+        case egl_connection_t::GLES_UPDATED_STANDALONE_DRIVER: {
+            android_namespace_t* ns = android::GraphicsEnv::getInstance().getDriverNamespace();
+            void* dso = load_updated_driver("GLESv1_CM", ns);
+            if (dso) {
+                initialize_api(dso, cnx, GLESv1_CM);
+                hnd->set(dso, GLESv1_CM);
+            }
+            break;
+        }
+        case egl_connection_t::GLES_SYSTEM_STANDALONE_DRIVER: {
+            dso = load_system_driver("GLESv1_CM",
+                                     cnx->systemDriverUseProperty ? cnx->systemDriverProperty
+                                                                  : nullptr,
+                                     cnx->systemDriverUseExactName);
+            if (dso) {
+                initialize_api(dso, cnx, GLESv1_CM);
+                hnd->set(dso, GLESv1_CM);
+            }
+            break;
+        }
+        default: {
+            ALOGE("Bad loadedDriverType (%d)", cnx->loadedDriverType);
+            break;
+        }
+    }
+
+    if (!cnx->libGles1) {
+        cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+    }
+
+    LOG_ALWAYS_FATAL_IF(!cnx->libGles1, "couldn't load system OpenGL ES V1 wrapper libraries");
+
+    return dso ? true : false;
+}
+
 void Loader::initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask) {
     if (mask & EGL) {
         getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 6f31ab4..4199753 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -53,6 +53,8 @@
     void* open(egl_connection_t* cnx);
     void close(egl_connection_t* cnx);
 
+    bool load_glesv1_driver(egl_connection_t* cnx);
+
 private:
     Loader();
     driver_t* attempt_to_load_angle(egl_connection_t* cnx);
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 25b1009..768d3b5 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -202,6 +202,15 @@
     return cnx->dso ? EGL_TRUE : EGL_FALSE;
 }
 
+static EGLBoolean egl_init_glesv1_drivers_locked() {
+    // get our driver loader
+    Loader& loader(Loader::getInstance());
+
+    // dynamically load our GLESV1 implementation
+    egl_connection_t* cnx = &gEGLImpl;
+    return loader.load_glesv1_driver(cnx);
+}
+
 static pthread_mutex_t sInitDriverMutex = PTHREAD_MUTEX_INITIALIZER;
 
 EGLBoolean egl_init_drivers() {
@@ -212,6 +221,14 @@
     return res;
 }
 
+EGLBoolean egl_init_glesv1_drivers() {
+    EGLBoolean res;
+    pthread_mutex_lock(&sInitDriverMutex);
+    res = egl_init_glesv1_drivers_locked();
+    pthread_mutex_unlock(&sInitDriverMutex);
+    return res;
+}
+
 static pthread_mutex_t sLogPrintMutex = PTHREAD_MUTEX_INITIALIZER;
 static std::chrono::steady_clock::time_point sLogPrintTime;
 static constexpr std::chrono::seconds DURATION(1);
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 67d69b4..3b19b32 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -220,7 +220,7 @@
     if (cnx->dso) {
         EGLDisplay dpy = EGL_NO_DISPLAY;
 
-        if (cnx->useAngle) {
+        if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
             EGLint error;
             dpy = getPlatformDisplayAngle(display, cnx, attrib_list, &error);
             if (error != EGL_NONE) {
@@ -464,7 +464,7 @@
         egl_connection_t* const cnx = &gEGLImpl;
         if (cnx->dso && disp.state == egl_display_t::INITIALIZED) {
             // If we're using ANGLE reset any custom DisplayPlatform
-            if (cnx->useAngle) {
+            if (cnx->loadedDriverType == egl_connection_t::GLES_ANGLE_STANDALONE_DRIVER) {
                 angle::resetAnglePlatform(disp.dpy);
             }
             if (cnx->egl.eglTerminate(disp.dpy) == EGL_FALSE) {
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 5162ba4..e2bc5c6 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -277,6 +277,7 @@
 
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 extern EGLBoolean egl_init_drivers();
+extern EGLBoolean egl_init_glesv1_drivers();
 extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
 extern gl_hooks_t gHooksTrace;
 
@@ -956,44 +957,42 @@
             egl_context_t* const c = get_context(share_list);
             share_list = c->context;
         }
-        // b/111083885 - If we are presenting EGL 1.4 interface to apps
-        // error out on robust access attributes that are invalid
-        // in EGL 1.4 as the driver may be fine with them but dEQP expects
-        // tests to fail according to spec.
-        if (attrib_list && (cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0))) {
-            const EGLint* attrib_ptr = attrib_list;
-            while (*attrib_ptr != EGL_NONE) {
-                GLint attr = *attrib_ptr++;
-                GLint value = *attrib_ptr++;
-                if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR) {
-                    // We are GL ES context with EGL 1.4, this is an invalid
-                    // attribute
+
+        // figure out if it's a GLESv1 or GLESv2
+        int gles_version_idx = egl_connection_t::GLESv1_INDEX;
+        if (attrib_list) {
+            const EGLint* ptr = attrib_list; // so that we don't modify attrib_list
+            while (*ptr != EGL_NONE) {
+                GLint attr = *ptr++;
+                GLint value = *ptr++;
+                if (attr == EGL_CONTEXT_CLIENT_VERSION) {
+                    if (value == 1) {
+                        gles_version_idx = egl_connection_t::GLESv1_INDEX;
+                    } else if (value == 2 || value == 3) {
+                        gles_version_idx = egl_connection_t::GLESv2_INDEX;
+                    }
+                } else if (attr == EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR &&
+                           cnx->driverVersion < EGL_MAKE_VERSION(1, 5, 0)) {
+                    // b/111083885 - If we are presenting EGL 1.4 interface to apps
+                    // error out on robust access attributes that are invalid
+                    // in EGL 1.4 as the driver may be fine with them but dEQP expects
+                    // tests to fail according to spec.
                     return setError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT);
                 }
-            };
+            }
         }
+
+        // GLESV1 driver is lazily loaded and initialized
+        if (gles_version_idx == egl_connection_t::GLESv1_INDEX) {
+            android::GraphicsEnv::getInstance().setTargetStats(
+                    android::GpuStatsInfo::Stats::GLES_1_IN_USE);
+            if (!egl_init_glesv1_drivers()) return EGL_NO_CONTEXT;
+        }
+
         EGLContext context = cnx->egl.eglCreateContext(
                 dp->disp.dpy, config, share_list, attrib_list);
         if (context != EGL_NO_CONTEXT) {
-            // figure out if it's a GLESv1 or GLESv2
-            int version = 0;
-            if (attrib_list) {
-                while (*attrib_list != EGL_NONE) {
-                    GLint attr = *attrib_list++;
-                    GLint value = *attrib_list++;
-                    if (attr == EGL_CONTEXT_CLIENT_VERSION) {
-                        if (value == 1) {
-                            version = egl_connection_t::GLESv1_INDEX;
-                            android::GraphicsEnv::getInstance().setTargetStats(
-                                    android::GpuStatsInfo::Stats::GLES_1_IN_USE);
-                        } else if (value == 2 || value == 3) {
-                            version = egl_connection_t::GLESv2_INDEX;
-                        }
-                    }
-                };
-            }
-            egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
-                    version);
+            egl_context_t* c = new egl_context_t(dpy, context, config, cnx, gles_version_idx);
             return c;
         }
     }
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 7bb9b59..4e9d7d0 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -17,11 +17,12 @@
 #ifndef ANDROID_EGLDEFS_H
 #define ANDROID_EGLDEFS_H
 
+#include <cutils/properties.h>
+#include <log/log.h>
+
 #include "../hooks.h"
 #include "egl_platform_entries.h"
 
-#include <log/log.h>
-
 #define VERSION_MAJOR 1
 #define VERSION_MINOR 4
 #define EGL_MAKE_VERSION(major, minor, patch) (((major) << 22) | ((minor) << 12) | (patch))
@@ -44,6 +45,15 @@
         GLESv2_INDEX = 1
     };
 
+    enum {
+        GLES_NO_DRIVER = 0, // no driver is loaded
+        GLES_SYSTEM_COMBO_DRIVER = 1, // GLES combo driver in system folder is loaded
+        GLES_SYSTEM_STANDALONE_DRIVER = 2, // standalone system drivers are loaded
+        GLES_ANGLE_STANDALONE_DRIVER = 3, // ANGLE (always standalone) drivers are loaded.
+        GLES_UPDATED_COMBO_DRIVER = 4, // GLES combo driver in updated driver folder is loaded
+        GLES_UPDATED_STANDALONE_DRIVER = 5, // standalone drivers in updated driver folder are loaded
+    };
+
     inline egl_connection_t() : dso(nullptr),
                                 libEgl(nullptr),
                                 libGles1(nullptr),
@@ -83,9 +93,12 @@
     bool                systemDriverUnloaded;
     bool                shouldUseAngle; // Should we attempt to load ANGLE
     bool                angleDecided;   // Have we tried to load ANGLE
-    bool                useAngle;       // Was ANGLE successfully loaded
     EGLint              angleBackend;
+    int                 loadedDriverType;
     void*               vendorEGL;
+    bool                systemDriverUseExactName;
+    bool                systemDriverUseProperty;
+    char                systemDriverProperty[PROPERTY_VALUE_MAX + 1];
 };
 // clang-format on
 
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index a0bd4e2..4dcc1ca 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -48,8 +48,7 @@
     }
 
     uint32_t width, height;
-    if (mainDpyInfo.orientation != DISPLAY_ORIENTATION_0 &&
-            mainDpyInfo.orientation != DISPLAY_ORIENTATION_180) {
+    if (mainDpyInfo.orientation != ui::ROTATION_0 && mainDpyInfo.orientation != ui::ROTATION_180) {
         // rotated
         width = mainDpyInfo.h;
         height = mainDpyInfo.w;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index ce7399e..77bf1e9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -256,6 +256,67 @@
     return currentTime - entry.eventTime >= STALE_EVENT_TIMEOUT;
 }
 
+static std::unique_ptr<DispatchEntry> createDispatchEntry(const InputTarget& inputTarget,
+                                                          EventEntry* eventEntry,
+                                                          int32_t inputTargetFlags) {
+    if (inputTarget.useDefaultPointerInfo()) {
+        const PointerInfo& pointerInfo = inputTarget.getDefaultPointerInfo();
+        return std::make_unique<DispatchEntry>(eventEntry, // increments ref
+                                               inputTargetFlags, pointerInfo.xOffset,
+                                               pointerInfo.yOffset, inputTarget.globalScaleFactor,
+                                               pointerInfo.windowXScale, pointerInfo.windowYScale);
+    }
+
+    ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
+    const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
+
+    PointerCoords pointerCoords[MAX_POINTERS];
+
+    // Use the first pointer information to normalize all other pointers. This could be any pointer
+    // as long as all other pointers are normalized to the same value and the final DispatchEntry
+    // uses the offset and scale for the normalized pointer.
+    const PointerInfo& firstPointerInfo =
+            inputTarget.pointerInfos[inputTarget.pointerIds.firstMarkedBit()];
+
+    // Iterate through all pointers in the event to normalize against the first.
+    for (uint32_t pointerIndex = 0; pointerIndex < motionEntry.pointerCount; pointerIndex++) {
+        const PointerProperties& pointerProperties = motionEntry.pointerProperties[pointerIndex];
+        uint32_t pointerId = uint32_t(pointerProperties.id);
+        const PointerInfo& currPointerInfo = inputTarget.pointerInfos[pointerId];
+
+        // The scale factor is the ratio of the current pointers scale to the normalized scale.
+        float scaleXDiff = currPointerInfo.windowXScale / firstPointerInfo.windowXScale;
+        float scaleYDiff = currPointerInfo.windowYScale / firstPointerInfo.windowYScale;
+
+        pointerCoords[pointerIndex].copyFrom(motionEntry.pointerCoords[pointerIndex]);
+        // First apply the current pointers offset to set the window at 0,0
+        pointerCoords[pointerIndex].applyOffset(currPointerInfo.xOffset, currPointerInfo.yOffset);
+        // Next scale the coordinates.
+        pointerCoords[pointerIndex].scale(1, scaleXDiff, scaleYDiff);
+        // Lastly, offset the coordinates so they're in the normalized pointer's frame.
+        pointerCoords[pointerIndex].applyOffset(-firstPointerInfo.xOffset,
+                                                -firstPointerInfo.yOffset);
+    }
+
+    MotionEntry* combinedMotionEntry =
+            new MotionEntry(motionEntry.sequenceNum, motionEntry.eventTime, motionEntry.deviceId,
+                            motionEntry.source, motionEntry.displayId, motionEntry.policyFlags,
+                            motionEntry.action, motionEntry.actionButton, motionEntry.flags,
+                            motionEntry.metaState, motionEntry.buttonState,
+                            motionEntry.classification, motionEntry.edgeFlags,
+                            motionEntry.xPrecision, motionEntry.yPrecision,
+                            motionEntry.xCursorPosition, motionEntry.yCursorPosition,
+                            motionEntry.downTime, motionEntry.pointerCount,
+                            motionEntry.pointerProperties, pointerCoords, 0 /* xOffset */,
+                            0 /* yOffset */);
+
+    return std::make_unique<DispatchEntry>(combinedMotionEntry, // increments ref
+                                           inputTargetFlags, firstPointerInfo.xOffset,
+                                           firstPointerInfo.yOffset, inputTarget.globalScaleFactor,
+                                           firstPointerInfo.windowXScale,
+                                           firstPointerInfo.windowYScale);
+}
+
 // --- InputDispatcherThread ---
 
 class InputDispatcher::InputDispatcherThread : public Thread {
@@ -1815,23 +1876,34 @@
 void InputDispatcher::addWindowTargetLocked(const sp<InputWindowHandle>& windowHandle,
                                             int32_t targetFlags, BitSet32 pointerIds,
                                             std::vector<InputTarget>& inputTargets) {
-    sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
-    if (inputChannel == nullptr) {
-        ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
-        return;
-    }
+    std::vector<InputTarget>::iterator it =
+            std::find_if(inputTargets.begin(), inputTargets.end(),
+                         [&windowHandle](const InputTarget& inputTarget) {
+                             return inputTarget.inputChannel->getConnectionToken() ==
+                                     windowHandle->getToken();
+                         });
 
     const InputWindowInfo* windowInfo = windowHandle->getInfo();
-    InputTarget target;
-    target.inputChannel = inputChannel;
-    target.flags = targetFlags;
-    target.xOffset = -windowInfo->frameLeft;
-    target.yOffset = -windowInfo->frameTop;
-    target.globalScaleFactor = windowInfo->globalScaleFactor;
-    target.windowXScale = windowInfo->windowXScale;
-    target.windowYScale = windowInfo->windowYScale;
-    target.pointerIds = pointerIds;
-    inputTargets.push_back(target);
+
+    if (it == inputTargets.end()) {
+        InputTarget inputTarget;
+        sp<InputChannel> inputChannel = getInputChannelLocked(windowHandle->getToken());
+        if (inputChannel == nullptr) {
+            ALOGW("Window %s already unregistered input channel", windowHandle->getName().c_str());
+            return;
+        }
+        inputTarget.inputChannel = inputChannel;
+        inputTarget.flags = targetFlags;
+        inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
+        inputTargets.push_back(inputTarget);
+        it = inputTargets.end() - 1;
+    }
+
+    ALOG_ASSERT(it->flags == targetFlags);
+    ALOG_ASSERT(it->globalScaleFactor == windowInfo->globalScaleFactor);
+
+    it->addPointers(pointerIds, -windowInfo->frameLeft, -windowInfo->frameTop,
+                    windowInfo->windowXScale, windowInfo->windowYScale);
 }
 
 void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
@@ -1854,10 +1926,7 @@
     InputTarget target;
     target.inputChannel = monitor.inputChannel;
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
-    target.xOffset = xOffset;
-    target.yOffset = yOffset;
-    target.pointerIds.clear();
-    target.globalScaleFactor = 1.0f;
+    target.setDefaultPointerInfo(xOffset, yOffset, 1 /* windowXScale */, 1 /* windowYScale */);
     inputTargets.push_back(target);
 }
 
@@ -2089,11 +2158,10 @@
     }
 #if DEBUG_DISPATCH_CYCLE
     ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, "
-          "xOffset=%f, yOffset=%f, globalScaleFactor=%f, "
-          "windowScaleFactor=(%f, %f), pointerIds=0x%x",
-          connection->getInputChannelName().c_str(), inputTarget.flags, inputTarget.xOffset,
-          inputTarget.yOffset, inputTarget.globalScaleFactor, inputTarget.windowXScale,
-          inputTarget.windowYScale, inputTarget.pointerIds.value);
+          "globalScaleFactor=%f, pointerIds=0x%x %s",
+          connection->getInputChannelName().c_str(), inputTarget.flags,
+          inputTarget.globalScaleFactor, inputTarget.pointerIds.value,
+          inputTarget.getPointerInfoString().c_str());
 #endif
 
     // Skip this event if the connection status is not normal.
@@ -2187,15 +2255,15 @@
     // This is a new event.
     // Enqueue a new dispatch entry onto the outbound queue for this connection.
     std::unique_ptr<DispatchEntry> dispatchEntry =
-            std::make_unique<DispatchEntry>(eventEntry, // increments ref
-                                            inputTargetFlags, inputTarget.xOffset,
-                                            inputTarget.yOffset, inputTarget.globalScaleFactor,
-                                            inputTarget.windowXScale, inputTarget.windowYScale);
+            createDispatchEntry(inputTarget, eventEntry, inputTargetFlags);
 
+    // Use the eventEntry from dispatchEntry since the entry may have changed and can now be a
+    // different EventEntry than what was passed in.
+    EventEntry* newEntry = dispatchEntry->eventEntry;
     // Apply target flags and update the connection's input state.
-    switch (eventEntry->type) {
+    switch (newEntry->type) {
         case EventEntry::Type::KEY: {
-            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*eventEntry);
+            const KeyEntry& keyEntry = static_cast<const KeyEntry&>(*newEntry);
             dispatchEntry->resolvedAction = keyEntry.action;
             dispatchEntry->resolvedFlags = keyEntry.flags;
 
@@ -2211,7 +2279,7 @@
         }
 
         case EventEntry::Type::MOTION: {
-            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*eventEntry);
+            const MotionEntry& motionEntry = static_cast<const MotionEntry&>(*newEntry);
             if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) {
                 dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE;
             } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) {
@@ -2265,14 +2333,14 @@
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
             LOG_ALWAYS_FATAL("%s events should not go to apps",
-                             EventEntry::typeToString(eventEntry->type));
+                             EventEntry::typeToString(newEntry->type));
             break;
         }
     }
 
     // Remember that we are waiting for this dispatch to complete.
     if (dispatchEntry->hasForegroundTarget()) {
-        incrementPendingForegroundDispatches(eventEntry);
+        incrementPendingForegroundDispatches(newEntry);
     }
 
     // Enqueue the dispatch entry.
@@ -2661,15 +2729,9 @@
                     getWindowHandleLocked(connection->inputChannel->getConnectionToken());
             if (windowHandle != nullptr) {
                 const InputWindowInfo* windowInfo = windowHandle->getInfo();
-                target.xOffset = -windowInfo->frameLeft;
-                target.yOffset = -windowInfo->frameTop;
+                target.setDefaultPointerInfo(-windowInfo->frameLeft, -windowInfo->frameTop,
+                                             windowInfo->windowXScale, windowInfo->windowYScale);
                 target.globalScaleFactor = windowInfo->globalScaleFactor;
-                target.windowXScale = windowInfo->windowXScale;
-                target.windowYScale = windowInfo->windowYScale;
-            } else {
-                target.xOffset = 0;
-                target.yOffset = 0;
-                target.globalScaleFactor = 1.0f;
             }
             target.inputChannel = connection->inputChannel;
             target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
diff --git a/services/inputflinger/dispatcher/InputTarget.cpp b/services/inputflinger/dispatcher/InputTarget.cpp
index 80fa2cb..0588374 100644
--- a/services/inputflinger/dispatcher/InputTarget.cpp
+++ b/services/inputflinger/dispatcher/InputTarget.cpp
@@ -42,4 +42,63 @@
     return StringPrintf("%" PRId32, dispatchMode);
 }
 
+void InputTarget::addPointers(BitSet32 newPointerIds, float xOffset, float yOffset,
+                              float windowXScale, float windowYScale) {
+    // The pointerIds can be empty, but still a valid InputTarget. This can happen for Monitors
+    // and non splittable windows since we will just use all the pointers from the input event.
+    if (newPointerIds.isEmpty()) {
+        setDefaultPointerInfo(xOffset, yOffset, windowXScale, windowYScale);
+        return;
+    }
+
+    // Ensure that the new set of pointers doesn't overlap with the current set of pointers.
+    ALOG_ASSERT((pointerIds & newPointerIds) == 0);
+
+    pointerIds |= newPointerIds;
+    while (!newPointerIds.isEmpty()) {
+        int32_t pointerId = newPointerIds.clearFirstMarkedBit();
+        pointerInfos[pointerId].xOffset = xOffset;
+        pointerInfos[pointerId].yOffset = yOffset;
+        pointerInfos[pointerId].windowXScale = windowXScale;
+        pointerInfos[pointerId].windowYScale = windowYScale;
+    }
+}
+
+void InputTarget::setDefaultPointerInfo(float xOffset, float yOffset, float windowXScale,
+                                        float windowYScale) {
+    pointerIds.clear();
+    pointerInfos[0].xOffset = xOffset;
+    pointerInfos[0].yOffset = yOffset;
+    pointerInfos[0].windowXScale = windowXScale;
+    pointerInfos[0].windowYScale = windowYScale;
+}
+
+bool InputTarget::useDefaultPointerInfo() const {
+    return pointerIds.isEmpty();
+}
+
+const PointerInfo& InputTarget::getDefaultPointerInfo() const {
+    return pointerInfos[0];
+}
+
+std::string InputTarget::getPointerInfoString() const {
+    if (useDefaultPointerInfo()) {
+        const PointerInfo& pointerInfo = getDefaultPointerInfo();
+        return StringPrintf("xOffset=%.1f, yOffset=%.1f windowScaleFactor=(%.1f, %.1f)",
+                            pointerInfo.xOffset, pointerInfo.yOffset, pointerInfo.windowXScale,
+                            pointerInfo.windowYScale);
+    }
+
+    std::string out;
+    for (uint32_t i = pointerIds.firstMarkedBit(); i <= pointerIds.lastMarkedBit(); i++) {
+        if (!pointerIds.hasBit(i)) {
+            continue;
+        }
+        out += StringPrintf("\n  pointerId %d: xOffset=%.1f, yOffset=%.1f "
+                            "windowScaleFactor=(%.1f, %.1f)",
+                            i, pointerInfos[i].xOffset, pointerInfos[i].yOffset,
+                            pointerInfos[i].windowXScale, pointerInfos[i].windowYScale);
+    }
+    return out;
+}
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 1ba5eff..499a75f 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -24,6 +24,22 @@
 namespace android::inputdispatcher {
 
 /*
+ * Information about each pointer for an InputTarget. This includes offset and scale so
+ * all pointers can be normalized to a single offset and scale.
+ *
+ * These values are ignored for KeyEvents
+ */
+struct PointerInfo {
+    // The x and y offset to add to a MotionEvent as it is delivered.
+    float xOffset = 0.0f;
+    float yOffset = 0.0f;
+
+    // Scaling factor to apply to MotionEvent as it is delivered.
+    float windowXScale = 1.0f;
+    float windowYScale = 1.0f;
+};
+
+/*
  * An input target specifies how an input event is to be dispatched to a particular window
  * including the window's input channel, control flags, a timeout, and an X / Y offset to
  * be added to input event coordinates to compensate for the absolute position of the
@@ -95,20 +111,37 @@
     // Flags for the input target.
     int32_t flags = 0;
 
-    // The x and y offset to add to a MotionEvent as it is delivered.
-    // (ignored for KeyEvents)
-    float xOffset = 0.0f;
-    float yOffset = 0.0f;
-
     // Scaling factor to apply to MotionEvent as it is delivered.
     // (ignored for KeyEvents)
     float globalScaleFactor = 1.0f;
-    float windowXScale = 1.0f;
-    float windowYScale = 1.0f;
 
     // The subset of pointer ids to include in motion events dispatched to this input target
     // if FLAG_SPLIT is set.
     BitSet32 pointerIds;
+    // The data is stored by the pointerId. Use the bit position of pointerIds to look up
+    // PointerInfo per pointerId.
+    PointerInfo pointerInfos[MAX_POINTERS];
+
+    void addPointers(BitSet32 pointerIds, float xOffset, float yOffset, float windowXScale,
+                     float windowYScale);
+    void setDefaultPointerInfo(float xOffset, float yOffset, float windowXScale,
+                               float windowYScale);
+
+    /**
+     * Returns whether the default pointer information should be used. This will be true when the
+     * InputTarget doesn't have any bits set in the pointerIds bitset. This can happen for monitors
+     * and non splittable windows since we want all pointers for the EventEntry to go to this
+     * target.
+     */
+    bool useDefaultPointerInfo() const;
+
+    /**
+     * Returns the default PointerInfo object. This should be used when useDefaultPointerInfo is
+     * true.
+     */
+    const PointerInfo& getDefaultPointerInfo() const;
+
+    std::string getPointerInfoString() const;
 };
 
 std::string dispatchModeToString(int32_t dispatchMode);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index c262abb..98ebf50 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -1571,4 +1571,107 @@
     consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, {expectedPoint});
 }
 
+TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchDifferentScale) {
+    mWindow2->setWindowScale(0.5f, 0.5f);
+
+    // Touch Window 1
+    std::vector<PointF> touchedPoints = {PointF{10, 10}};
+    std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
+
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, expectedPoints);
+
+    // Touch Window 2
+    int32_t actionPointerDown =
+            AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+    touchedPoints.emplace_back(PointF{150, 150});
+    expectedPoints.emplace_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
+
+    motionArgs = generateMotionArgs(actionPointerDown, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+
+    // Consuming from window1 since it's the window that has the InputReceiver
+    consumeMotionEvent(mWindow1, actionPointerDown, expectedPoints);
+}
+
+TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleTouchMoveDifferentScale) {
+    mWindow2->setWindowScale(0.5f, 0.5f);
+
+    // Touch Window 1
+    std::vector<PointF> touchedPoints = {PointF{10, 10}};
+    std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
+
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, expectedPoints);
+
+    // Touch Window 2
+    int32_t actionPointerDown =
+            AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+    touchedPoints.emplace_back(PointF{150, 150});
+    expectedPoints.emplace_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
+
+    motionArgs = generateMotionArgs(actionPointerDown, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+
+    // Consuming from window1 since it's the window that has the InputReceiver
+    consumeMotionEvent(mWindow1, actionPointerDown, expectedPoints);
+
+    // Move both windows
+    touchedPoints = {{20, 20}, {175, 175}};
+    expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
+                      getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
+
+    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_MOVE, expectedPoints);
+}
+
+TEST_F(InputDispatcherMultiWindowSameTokenTests, MultipleWindowsFirstTouchWithScale) {
+    mWindow1->setWindowScale(0.5f, 0.5f);
+
+    // Touch Window 1
+    std::vector<PointF> touchedPoints = {PointF{10, 10}};
+    std::vector<PointF> expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0])};
+
+    NotifyMotionArgs motionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_DOWN, expectedPoints);
+
+    // Touch Window 2
+    int32_t actionPointerDown =
+            AMOTION_EVENT_ACTION_POINTER_DOWN + (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+    touchedPoints.emplace_back(PointF{150, 150});
+    expectedPoints.emplace_back(getPointInWindow(mWindow2->getInfo(), touchedPoints[1]));
+
+    motionArgs = generateMotionArgs(actionPointerDown, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+
+    // Consuming from window1 since it's the window that has the InputReceiver
+    consumeMotionEvent(mWindow1, actionPointerDown, expectedPoints);
+
+    // Move both windows
+    touchedPoints = {{20, 20}, {175, 175}};
+    expectedPoints = {getPointInWindow(mWindow1->getInfo(), touchedPoints[0]),
+                      getPointInWindow(mWindow2->getInfo(), touchedPoints[1])};
+
+    motionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                                    ADISPLAY_ID_DEFAULT, touchedPoints);
+    mDispatcher->notifyMotion(&motionArgs);
+
+    consumeMotionEvent(mWindow1, AMOTION_EVENT_ACTION_MOVE, expectedPoints);
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index bdecdb7..3b1b796 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -207,7 +207,7 @@
              * the code below applies the primary display's inverse transform to
              * the texture transform
              */
-            uint32_t transform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+            uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
             mat4 tr = inverseOrientation(transform);
 
             /**
@@ -622,7 +622,7 @@
     }
 
     if (getTransformToDisplayInverse()) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
         if (invTransform & ui::Transform::ROT_90) {
             std::swap(bufWidth, bufHeight);
         }
@@ -658,7 +658,7 @@
     }
 
     if (getTransformToDisplayInverse()) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
         if (invTransform & ui::Transform::ROT_90) {
             std::swap(bufWidth, bufHeight);
         }
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 1e471e5..067aa46 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -344,6 +344,11 @@
     return willPresent;
 }
 
+void BufferStateLayer::forceSendCallbacks() {
+    mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
+            mCurrentState.callbackHandles);
+}
+
 bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
     mCurrentState.transparentRegionHint = transparent;
     mCurrentState.modified = true;
@@ -468,7 +473,7 @@
     }
 
     if (s.transformToDisplayInverse) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
         if (invTransform & ui::Transform::ROT_90) {
             std::swap(bufferWidth, bufferHeight);
         }
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 8e6a70c..574bc51 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -77,6 +77,7 @@
     bool setApi(int32_t api) override;
     bool setSidebandStream(const sp<NativeHandle>& sidebandStream) override;
     bool setTransactionCompletedListeners(const std::vector<sp<CallbackHandle>>& handles) override;
+    void forceSendCallbacks() override;
 
     // Override to ignore legacy layer state properties that are not used by BufferStateLayer
     bool setSize(uint32_t /*w*/, uint32_t /*h*/) override { return false; }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 84ec597..e0dc3e7 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -41,12 +41,7 @@
 
 using android::base::StringAppendF;
 
-/*
- * Initialize the display to the specified values.
- *
- */
-
-uint32_t DisplayDevice::sPrimaryDisplayOrientation = 0;
+ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
 
 DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(const sp<SurfaceFlinger>& flinger,
                                                      const wp<IBinder>& displayToken,
@@ -57,13 +52,11 @@
       : mFlinger(args.flinger),
         mDisplayToken(args.displayToken),
         mSequenceId(args.sequenceId),
-        mDisplayInstallOrientation(args.displayInstallOrientation),
+        mIsVirtual(args.isVirtual),
         mCompositionDisplay{mFlinger->getCompositionEngine().createDisplay(
                 compositionengine::DisplayCreationArgs{args.isVirtual, args.displayId,
                                                        args.powerAdvisor})},
-        mIsVirtual(args.isVirtual),
-        mOrientation(),
-        mActiveConfig(0),
+        mPhysicalOrientation(args.physicalOrientation),
         mIsPrimary(args.isPrimary) {
     mCompositionDisplay->editState().isSecure = args.isSecure;
     mCompositionDisplay->createRenderSurface(
@@ -88,7 +81,7 @@
     setPowerMode(args.initialPowerMode);
 
     // initialize the display orientation transform.
-    setProjection(DisplayState::eOrientationDefault, Rect::INVALID_RECT, Rect::INVALID_RECT);
+    setProjection(ui::ROTATION_0, Rect::INVALID_RECT, Rect::INVALID_RECT);
 }
 
 DisplayDevice::~DisplayDevice() = default;
@@ -131,7 +124,6 @@
     return mPowerMode != HWC_POWER_MODE_OFF;
 }
 
-// ----------------------------------------------------------------------------
 void DisplayDevice::setActiveConfig(HwcConfigIndexType mode) {
     mActiveConfig = mode;
 }
@@ -140,53 +132,19 @@
     return mActiveConfig;
 }
 
-// ----------------------------------------------------------------------------
-
 ui::Dataspace DisplayDevice::getCompositionDataSpace() const {
     return mCompositionDisplay->getState().dataspace;
 }
 
-// ----------------------------------------------------------------------------
-
 void DisplayDevice::setLayerStack(uint32_t stack) {
     mCompositionDisplay->setLayerStackFilter(stack, isPrimary());
 }
 
-// ----------------------------------------------------------------------------
-
-uint32_t DisplayDevice::displayStateOrientationToTransformOrientation(int orientation) {
-    switch (orientation) {
-    case DisplayState::eOrientationDefault:
-        return ui::Transform::ROT_0;
-    case DisplayState::eOrientation90:
-        return ui::Transform::ROT_90;
-    case DisplayState::eOrientation180:
-        return ui::Transform::ROT_180;
-    case DisplayState::eOrientation270:
-        return ui::Transform::ROT_270;
-    default:
-        return ui::Transform::ROT_INVALID;
-    }
-}
-
-status_t DisplayDevice::orientationToTransfrom(int orientation, int w, int h, ui::Transform* tr) {
-    uint32_t flags = displayStateOrientationToTransformOrientation(orientation);
-    if (flags == ui::Transform::ROT_INVALID) {
-        return BAD_VALUE;
-    }
-    tr->set(flags, w, h);
-    return NO_ERROR;
-}
-
 void DisplayDevice::setDisplaySize(const int newWidth, const int newHeight) {
     mCompositionDisplay->setBounds(ui::Size(newWidth, newHeight));
 }
 
-void DisplayDevice::setProjection(int orientation,
-        const Rect& newViewport, const Rect& newFrame) {
-    Rect viewport(newViewport);
-    Rect frame(newFrame);
-
+void DisplayDevice::setProjection(ui::Rotation orientation, Rect viewport, Rect frame) {
     mOrientation = orientation;
 
     const Rect& displayBounds = getCompositionDisplay()->getState().bounds;
@@ -194,7 +152,10 @@
     const int h = displayBounds.height();
 
     ui::Transform R;
-    DisplayDevice::orientationToTransfrom(orientation, w, h, &R);
+    if (const auto flags = ui::Transform::toRotationFlags(orientation);
+        flags != ui::Transform::ROT_INVALID) {
+        R.set(flags, w, h);
+    }
 
     if (!frame.isValid()) {
         // the destination frame can be invalid if it has never been set,
@@ -236,9 +197,10 @@
     // need to take care of primary display rotation for globalTransform
     // for case if the panel is not installed aligned with device orientation
     if (isPrimary()) {
-        DisplayDevice::orientationToTransfrom(
-                (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1),
-                w, h, &R);
+        if (const auto flags = ui::Transform::toRotationFlags(orientation + mPhysicalOrientation);
+            flags != ui::Transform::ROT_INVALID) {
+            R.set(flags, w, h);
+        }
     }
 
     // The viewport and frame are both in the logical orientation.
@@ -258,19 +220,18 @@
     uint32_t transformOrientation;
 
     if (isPrimary()) {
-        sPrimaryDisplayOrientation = displayStateOrientationToTransformOrientation(orientation);
-        transformOrientation = displayStateOrientationToTransformOrientation(
-                (orientation + mDisplayInstallOrientation) % (DisplayState::eOrientation270 + 1));
+        sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
+        transformOrientation = ui::Transform::toRotationFlags(orientation + mPhysicalOrientation);
     } else {
-        transformOrientation = displayStateOrientationToTransformOrientation(orientation);
+        transformOrientation = ui::Transform::toRotationFlags(orientation);
     }
 
     getCompositionDisplay()->setProjection(globalTransform, transformOrientation,
                                            frame, viewport, scissor, needsFiltering);
 }
 
-uint32_t DisplayDevice::getPrimaryDisplayOrientationTransform() {
-    return sPrimaryDisplayOrientation;
+ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
+    return sPrimaryDisplayRotationFlags;
 }
 
 std::string DisplayDevice::getDebugName() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 79a1185..605e7c8 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#ifndef ANDROID_DISPLAY_DEVICE_H
-#define ANDROID_DISPLAY_DEVICE_H
+#pragma once
 
 #include <stdlib.h>
 
@@ -83,14 +82,17 @@
 
     int         getWidth() const;
     int         getHeight() const;
-    int         getInstallOrientation() const { return mDisplayInstallOrientation; }
 
     void                    setLayerStack(uint32_t stack);
     void                    setDisplaySize(const int newWidth, const int newHeight);
-    void                    setProjection(int orientation, const Rect& viewport, const Rect& frame);
 
-    int                     getOrientation() const { return mOrientation; }
-    static uint32_t         getPrimaryDisplayOrientationTransform();
+    void setProjection(ui::Rotation orientation, Rect viewport, Rect frame);
+
+    ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
+    ui::Rotation getOrientation() const { return mOrientation; }
+
+    static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
+
     const ui::Transform& getTransform() const;
     const Rect& getViewport() const;
     const Rect& getFrame() const;
@@ -156,37 +158,21 @@
     void dump(std::string& result) const;
 
 private:
-    /*
-     *  Constants, set during initialization
-     */
     const sp<SurfaceFlinger> mFlinger;
     const wp<IBinder> mDisplayToken;
     const int32_t mSequenceId;
+    const bool mIsVirtual;
 
-    const int mDisplayInstallOrientation;
     const std::shared_ptr<compositionengine::Display> mCompositionDisplay;
 
     std::string mDisplayName;
-    const bool mIsVirtual;
 
-    /*
-     * Can only accessed from the main thread, these members
-     * don't need synchronization.
-     */
+    const ui::Rotation mPhysicalOrientation;
+    ui::Rotation mOrientation = ui::ROTATION_0;
 
-    /*
-     * Transaction state
-     */
-    static uint32_t displayStateOrientationToTransformOrientation(int orientation);
-    static status_t orientationToTransfrom(int orientation,
-                                           int w, int h, ui::Transform* tr);
+    static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
 
-    int mOrientation;
-    static uint32_t sPrimaryDisplayOrientation;
-
-    // Current power mode
-    int mPowerMode;
-    // Current active config
+    int mPowerMode = HWC_POWER_MODE_OFF;
     HwcConfigIndexType mActiveConfig;
 
     // TODO(b/74619554): Remove special cases for primary display.
@@ -202,7 +188,7 @@
     uint32_t layerStack = NO_LAYER_STACK;
     Rect viewport;
     Rect frame;
-    uint8_t orientation = 0;
+    ui::Rotation orientation = ui::ROTATION_0;
     uint32_t width = 0;
     uint32_t height = 0;
     std::string displayName;
@@ -227,7 +213,7 @@
     bool isSecure{false};
     sp<ANativeWindow> nativeWindow;
     sp<compositionengine::DisplaySurface> displaySurface;
-    int displayInstallOrientation{DisplayState::eOrientationDefault};
+    ui::Rotation physicalOrientation{ui::ROTATION_0};
     bool hasWideColorGamut{false};
     HdrCapabilities hdrCapabilities;
     int32_t supportedPerFrameMetadata{0};
@@ -239,31 +225,33 @@
 
 class DisplayRenderArea : public RenderArea {
 public:
-    DisplayRenderArea(const sp<const DisplayDevice> device,
-                      ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
-          : DisplayRenderArea(device, device->getBounds(), device->getWidth(), device->getHeight(),
-                              device->getCompositionDataSpace(), rotation) {}
-    DisplayRenderArea(const sp<const DisplayDevice> device, Rect sourceCrop, uint32_t reqWidth,
-                      uint32_t reqHeight, ui::Dataspace reqDataSpace,
-                      ui::Transform::orientation_flags rotation, bool allowSecureLayers = true)
+    DisplayRenderArea(const sp<const DisplayDevice>& display,
+                      RotationFlags rotation = ui::Transform::ROT_0)
+          : DisplayRenderArea(display, display->getBounds(), display->getWidth(),
+                              display->getHeight(), display->getCompositionDataSpace(), rotation) {}
+
+    DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, uint32_t reqWidth,
+                      uint32_t reqHeight, ui::Dataspace reqDataSpace, RotationFlags rotation,
+                      bool allowSecureLayers = true)
           : RenderArea(reqWidth, reqHeight, CaptureFill::OPAQUE, reqDataSpace,
-                       device->getViewport(),
-                       getDisplayRotation(rotation, device->getInstallOrientation())),
-            mDevice(device),
+                       display->getViewport(),
+                       applyInversePhysicalOrientation(rotation,
+                                                       display->getPhysicalOrientation())),
+            mDisplay(std::move(display)),
             mSourceCrop(sourceCrop),
             mAllowSecureLayers(allowSecureLayers) {}
 
-    const ui::Transform& getTransform() const override { return mDevice->getTransform(); }
-    Rect getBounds() const override { return mDevice->getBounds(); }
-    int getHeight() const override { return mDevice->getHeight(); }
-    int getWidth() const override { return mDevice->getWidth(); }
-    bool isSecure() const override { return mAllowSecureLayers && mDevice->isSecure(); }
-    const sp<const DisplayDevice> getDisplayDevice() const override { return mDevice; }
+    const ui::Transform& getTransform() const override { return mDisplay->getTransform(); }
+    Rect getBounds() const override { return mDisplay->getBounds(); }
+    int getHeight() const override { return mDisplay->getHeight(); }
+    int getWidth() const override { return mDisplay->getWidth(); }
+    bool isSecure() const override { return mAllowSecureLayers && mDisplay->isSecure(); }
+    sp<const DisplayDevice> getDisplayDevice() const override { return mDisplay; }
 
     bool needsFiltering() const override {
         // check if the projection from the logical display to the physical
         // display needs filtering
-        if (mDevice->needsFiltering()) {
+        if (mDisplay->needsFiltering()) {
             return true;
         }
 
@@ -281,7 +269,7 @@
     Rect getSourceCrop() const override {
         // use the projected display viewport by default.
         if (mSourceCrop.isEmpty()) {
-            return mDevice->getScissor();
+            return mDisplay->getScissor();
         }
 
         // Recompute the device transformation for the source crop.
@@ -289,27 +277,13 @@
         ui::Transform translatePhysical;
         ui::Transform translateLogical;
         ui::Transform scale;
-        const Rect& viewport = mDevice->getViewport();
-        const Rect& scissor = mDevice->getScissor();
-        const Rect& frame = mDevice->getFrame();
+        const Rect& viewport = mDisplay->getViewport();
+        const Rect& scissor = mDisplay->getScissor();
+        const Rect& frame = mDisplay->getFrame();
 
-        const int orientation = mDevice->getInstallOrientation();
-        // Install orientation is transparent to the callers.  Apply it now.
-        uint32_t flags = 0x00;
-        switch (orientation) {
-            case DisplayState::eOrientation90:
-                flags = ui::Transform::ROT_90;
-                break;
-            case DisplayState::eOrientation180:
-                flags = ui::Transform::ROT_180;
-                break;
-            case DisplayState::eOrientation270:
-                flags = ui::Transform::ROT_270;
-                break;
-            default:
-                break;
-        }
+        const auto flags = ui::Transform::toRotationFlags(mDisplay->getPhysicalOrientation());
         rotation.set(flags, getWidth(), getHeight());
+
         translateLogical.set(-viewport.left, -viewport.top);
         translatePhysical.set(scissor.left, scissor.top);
         scale.set(frame.getWidth() / float(viewport.getWidth()), 0, 0,
@@ -320,49 +294,44 @@
     }
 
 private:
-    // Install orientation is transparent to the callers.  We need to cancel
-    // it out by modifying rotation flags.
-    static ui::Transform::orientation_flags getDisplayRotation(
-            ui::Transform::orientation_flags rotation, int orientation) {
-        if (orientation == DisplayState::eOrientationDefault) {
-            return rotation;
-        }
+    static RotationFlags applyInversePhysicalOrientation(RotationFlags orientation,
+                                                         ui::Rotation physicalOrientation) {
+        uint32_t inverseRotate90 = 0;
+        uint32_t inverseReflect = 0;
 
-        // convert hw orientation into flag presentation
-        // here inverse transform needed
-        uint8_t hw_rot_90 = 0x00;
-        uint8_t hw_flip_hv = 0x00;
-        switch (orientation) {
-            case DisplayState::eOrientation90:
-                hw_rot_90 = ui::Transform::ROT_90;
-                hw_flip_hv = ui::Transform::ROT_180;
+        switch (physicalOrientation) {
+            case ui::ROTATION_0:
+                return orientation;
+
+            case ui::ROTATION_90:
+                inverseRotate90 = ui::Transform::ROT_90;
+                inverseReflect = ui::Transform::ROT_180;
                 break;
-            case DisplayState::eOrientation180:
-                hw_flip_hv = ui::Transform::ROT_180;
+
+            case ui::ROTATION_180:
+                inverseReflect = ui::Transform::ROT_180;
                 break;
-            case DisplayState::eOrientation270:
-                hw_rot_90 = ui::Transform::ROT_90;
+
+            case ui::ROTATION_270:
+                inverseRotate90 = ui::Transform::ROT_90;
                 break;
         }
 
-        // transform flags operation
-        // 1) flip H V if both have ROT_90 flag
-        // 2) XOR these flags
-        uint8_t rotation_rot_90 = rotation & ui::Transform::ROT_90;
-        uint8_t rotation_flip_hv = rotation & ui::Transform::ROT_180;
-        if (rotation_rot_90 & hw_rot_90) {
-            rotation_flip_hv = (~rotation_flip_hv) & ui::Transform::ROT_180;
+        const uint32_t rotate90 = orientation & ui::Transform::ROT_90;
+        uint32_t reflect = orientation & ui::Transform::ROT_180;
+
+        // Apply reflection for double rotation.
+        if (rotate90 & inverseRotate90) {
+            reflect = ~reflect & ui::Transform::ROT_180;
         }
 
-        return static_cast<ui::Transform::orientation_flags>(
-                (rotation_rot_90 ^ hw_rot_90) | (rotation_flip_hv ^ hw_flip_hv));
+        return static_cast<RotationFlags>((rotate90 ^ inverseRotate90) |
+                                          (reflect ^ inverseReflect));
     }
 
-    const sp<const DisplayDevice> mDevice;
+    const sp<const DisplayDevice> mDisplay;
     const Rect mSourceCrop;
     const bool mAllowSecureLayers;
 };
 
-}; // namespace android
-
-#endif // ANDROID_DISPLAY_DEVICE_H
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 8b532e3..e7cf5ff 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -76,6 +76,7 @@
     virtual void onVsyncPeriodTimingChangedReceived(
             int32_t sequenceId, hwc2_display_t display,
             const hwc_vsync_period_change_timeline_t& updatedTimeline) = 0;
+    virtual void onSeamlessPossible(int32_t sequenceId, hwc2_display_t display) = 0;
 
     virtual ~ComposerCallback() = default;
 };
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 0a7009b..1960f43 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -125,6 +125,11 @@
         return android::hardware::Void();
     }
 
+    android::hardware::Return<void> onSeamlessPossible(android::Hwc2::Display display) override {
+        mCallback->onSeamlessPossible(mSequenceId, display);
+        return android::hardware::Void();
+    }
+
 private:
     HWC2::ComposerCallback* mCallback;
     const int32_t mSequenceId;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6fd1629..37714f5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -848,7 +848,7 @@
         // inevitably waiting on a buffer to return. We recreate this semantic for BufferQueue
         // even though it is a little consistent. detachChildren is shortly slated for removal
         // by the hierarchy mirroring work so we don't need to worry about it too much.
-        mDrawingState.callbackHandles = mCurrentState.callbackHandles;
+        forceSendCallbacks();
         mCurrentState.callbackHandles = {};
         return flags;
     }
@@ -1893,6 +1893,16 @@
     setTransactionFlags(eTransactionNeeded);
 }
 
+void Layer::writeToProto(LayersProto& layersProto, uint32_t traceFlags) const {
+    LayerProto* layerProto = layersProto.add_layers();
+    writeToProtoDrawingState(layerProto, traceFlags);
+    writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
+
+    for (const sp<Layer>& layer : mDrawingChildren) {
+        layer->writeToProto(layersProto, traceFlags);
+    }
+}
+
 void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const {
     ui::Transform transform = getTransform();
 
@@ -2014,6 +2024,8 @@
         } else {
             layerInfo->set_z_order_relative_of(-1);
         }
+
+        layerInfo->set_is_relative_of(state.isRelativeOf);
     }
 
     if (traceFlags & SurfaceTracing::TRACE_INPUT) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index d697a6a..76edfa5 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -333,6 +333,7 @@
             const std::vector<sp<CallbackHandle>>& /*handles*/) {
         return false;
     };
+    virtual void forceSendCallbacks() {}
     virtual bool setBackgroundColor(const half3& color, float alpha, ui::Dataspace dataspace);
     virtual bool setColorSpaceAgnostic(const bool agnostic);
     bool setShadowRadius(float shadowRadius);
@@ -453,6 +454,9 @@
 
     bool isRemovedFromCurrentState() const;
 
+    void writeToProto(LayersProto& layersProto,
+                      uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+
     // Write states that are modified by the main thread. This includes drawing
     // state as well as buffer data. This should be called in the main or tracing
     // thread.
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index 1a60f1e..412f977 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -49,7 +49,7 @@
     }
 
     if (mTransformToDisplayInverse) {
-        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
         if (invTransform & ui::Transform::ROT_90) {
             std::swap(bufWidth, bufHeight);
         }
diff --git a/services/surfaceflinger/OWNERS b/services/surfaceflinger/OWNERS
index 69d8c89..4ef64b6 100644
--- a/services/surfaceflinger/OWNERS
+++ b/services/surfaceflinger/OWNERS
@@ -5,4 +5,5 @@
 lpy@google.com
 marissaw@google.com
 racarr@google.com
-stoza@google.com
\ No newline at end of file
+stoza@google.com
+vhau@google.com
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index a484373..73de4f8 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -337,19 +337,7 @@
     }
 
     const auto device = mFlinger.getDefaultDisplayDevice();
-    const auto orientation = [](uint32_t orientation) {
-        switch (orientation) {
-            default:
-            case DisplayState::eOrientationDefault:
-                return ui::Transform::ROT_0;
-            case DisplayState::eOrientation90:
-                return ui::Transform::ROT_90;
-            case DisplayState::eOrientation180:
-                return ui::Transform::ROT_180;
-            case DisplayState::eOrientation270:
-                return ui::Transform::ROT_270;
-        }
-    }(device->getOrientation());
+    const auto orientation = ui::Transform::toRotationFlags(device->getOrientation());
 
     std::vector<RegionSamplingThread::Descriptor> descriptors;
     Region sampleRegion;
diff --git a/services/surfaceflinger/RenderArea.h b/services/surfaceflinger/RenderArea.h
index 532572f..a7a6dd5 100644
--- a/services/surfaceflinger/RenderArea.h
+++ b/services/surfaceflinger/RenderArea.h
@@ -17,13 +17,15 @@
 // physical render area.
 class RenderArea {
 public:
+    using RotationFlags = ui::Transform::RotationFlags;
+
     enum class CaptureFill {CLEAR, OPAQUE};
 
     static float getCaptureFillValue(CaptureFill captureFill);
 
     RenderArea(uint32_t reqWidth, uint32_t reqHeight, CaptureFill captureFill,
                ui::Dataspace reqDataSpace, const Rect& displayViewport,
-               ui::Transform::orientation_flags rotation = ui::Transform::ROT_0)
+               RotationFlags rotation = ui::Transform::ROT_0)
           : mReqWidth(reqWidth),
             mReqHeight(reqHeight),
             mReqDataSpace(reqDataSpace),
@@ -66,20 +68,20 @@
     virtual Rect getSourceCrop() const = 0;
 
     // Returns the rotation of the source crop and the layers.
-    ui::Transform::orientation_flags getRotationFlags() const { return mRotationFlags; };
+    RotationFlags getRotationFlags() const { return mRotationFlags; }
 
     // Returns the size of the physical render area.
-    int getReqWidth() const { return mReqWidth; };
-    int getReqHeight() const { return mReqHeight; };
+    int getReqWidth() const { return mReqWidth; }
+    int getReqHeight() const { return mReqHeight; }
 
     // Returns the composition data space of the render area.
     ui::Dataspace getReqDataSpace() const { return mReqDataSpace; }
 
     // Returns the fill color of the physical render area.  Regions not
     // covered by any rendered layer should be filled with this color.
-    CaptureFill getCaptureFill() const { return mCaptureFill; };
+    CaptureFill getCaptureFill() const { return mCaptureFill; }
 
-    virtual const sp<const DisplayDevice> getDisplayDevice() const = 0;
+    virtual sp<const DisplayDevice> getDisplayDevice() const = 0;
 
     // Returns the source display viewport.
     const Rect& getDisplayViewport() const { return mDisplayViewport; }
@@ -89,7 +91,7 @@
     const uint32_t mReqHeight;
     const ui::Dataspace mReqDataSpace;
     const CaptureFill mCaptureFill;
-    const ui::Transform::orientation_flags mRotationFlags;
+    const RotationFlags mRotationFlags;
     const Rect mDisplayViewport;
 };
 
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 146ec1b..cf79d9f 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -34,7 +34,7 @@
 #include "LayerInfo.h"
 #include "SchedulerUtils.h"
 
-namespace android::scheduler {
+namespace android::scheduler::impl {
 
 namespace {
 
@@ -157,4 +157,4 @@
     mActiveLayersEnd = 0;
 }
 
-} // namespace android::scheduler
+} // namespace android::scheduler::impl
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.h b/services/surfaceflinger/Scheduler/LayerHistory.h
index 745c4c1..d92e5c3 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.h
+++ b/services/surfaceflinger/Scheduler/LayerHistory.h
@@ -32,33 +32,51 @@
 
 namespace scheduler {
 
+class LayerHistoryTest;
 class LayerInfo;
 
-// Records per-layer history of scheduling-related information (primarily present time),
-// heuristically categorizes layers as active or inactive, and summarizes stats about
-// active layers (primarily maximum refresh rate). See go/content-fps-detection-in-scheduler.
 class LayerHistory {
 public:
-    LayerHistory();
-    ~LayerHistory();
+    virtual ~LayerHistory() = default;
 
     // Layers are unregistered when the weak reference expires.
-    void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate);
+    virtual void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate) = 0;
 
     // Marks the layer as active, and records the given state to its history.
-    void record(Layer*, nsecs_t presentTime, nsecs_t now);
+    virtual void record(Layer*, nsecs_t presentTime, nsecs_t now) = 0;
 
     struct Summary {
         float maxRefreshRate; // Maximum refresh rate among recently active layers.
     };
 
     // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
-    Summary summarize(nsecs_t now);
+    virtual Summary summarize(nsecs_t now) = 0;
 
-    void clear();
+    virtual void clear() = 0;
+};
+
+namespace impl {
+// Records per-layer history of scheduling-related information (primarily present time),
+// heuristically categorizes layers as active or inactive, and summarizes stats about
+// active layers (primarily maximum refresh rate). See go/content-fps-detection-in-scheduler.
+class LayerHistory : public android::scheduler::LayerHistory {
+public:
+    LayerHistory();
+    virtual ~LayerHistory();
+
+    // Layers are unregistered when the weak reference expires.
+    void registerLayer(Layer*, float lowRefreshRate, float highRefreshRate) override;
+
+    // Marks the layer as active, and records the given state to its history.
+    void record(Layer*, nsecs_t presentTime, nsecs_t now) override;
+
+    // Rebuilds sets of active/inactive layers, and accumulates stats for active layers.
+    android::scheduler::LayerHistory::Summary summarize(nsecs_t now) override;
+
+    void clear() override;
 
 private:
-    friend class LayerHistoryTest;
+    friend class android::scheduler::LayerHistoryTest;
     friend TestableScheduler;
 
     using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>;
@@ -90,5 +108,6 @@
     const bool mTraceEnabled;
 };
 
+} // namespace impl
 } // namespace scheduler
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index ff9cf86..73dc753 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -108,7 +108,7 @@
     using namespace sysprop;
 
     if (property_get_bool("debug.sf.use_smart_90_for_video", 0) || use_smart_90_for_video(false)) {
-        mLayerHistory.emplace();
+        mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
     }
 
     const int setIdleTimerMs = property_get_int32("debug.sf.set_idle_timer_ms", 0);
@@ -493,7 +493,7 @@
 
     const bool supported = mRefreshRateConfigs.refreshRateSwitchingSupported();
     StringAppendF(&result, "+  Refresh rate switching: %s\n", states[supported]);
-    StringAppendF(&result, "+  Content detection: %s\n", states[mLayerHistory.has_value()]);
+    StringAppendF(&result, "+  Content detection: %s\n", states[mLayerHistory != nullptr]);
 
     StringAppendF(&result, "+  Idle timer: %s\n",
                   mIdleTimer ? mIdleTimer->dump().c_str() : states[0]);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 2cdb757..c6430c3 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -193,7 +193,7 @@
     std::unique_ptr<EventControlThread> mEventControlThread;
 
     // Used to choose refresh rate if content detection is enabled.
-    std::optional<scheduler::LayerHistory> mLayerHistory;
+    std::unique_ptr<scheduler::LayerHistory> mLayerHistory;
 
     // Whether to use idle timer callbacks that support the kernel timer.
     const bool mSupportKernelTimer;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.cpp b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
index a652053..158a184 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.cpp
@@ -175,10 +175,25 @@
     return mTracker->nextAnticipatedVSyncTimeFrom(mClock->now());
 }
 
+void VSyncReactor::startPeriodTransition(nsecs_t newPeriod) {
+    mPeriodTransitioningTo = newPeriod;
+    mMoreSamplesNeeded = true;
+}
+
+void VSyncReactor::endPeriodTransition() {
+    mPeriodTransitioningTo.reset();
+    mLastHwVsync.reset();
+    mMoreSamplesNeeded = false;
+}
+
 void VSyncReactor::setPeriod(nsecs_t period) {
     std::lock_guard lk(mMutex);
     mLastHwVsync.reset();
-    mPeriodTransitioningTo = period;
+    if (period == getPeriod()) {
+        endPeriodTransition();
+    } else {
+        startPeriodTransition(period);
+    }
 }
 
 nsecs_t VSyncReactor::getPeriod() {
@@ -202,16 +217,13 @@
 
     std::lock_guard<std::mutex> lk(mMutex);
     if (periodChangeDetected(timestamp)) {
-        mMoreSamplesNeeded = false;
-        *periodFlushed = true;
-
         mTracker->setPeriod(*mPeriodTransitioningTo);
         for (auto& entry : mCallbacks) {
             entry.second->setPeriod(*mPeriodTransitioningTo);
         }
 
-        mPeriodTransitioningTo.reset();
-        mLastHwVsync.reset();
+        endPeriodTransition();
+        *periodFlushed = true;
     } else if (mPeriodTransitioningTo) {
         mLastHwVsync = timestamp;
         mMoreSamplesNeeded = true;
diff --git a/services/surfaceflinger/Scheduler/VSyncReactor.h b/services/surfaceflinger/Scheduler/VSyncReactor.h
index 73a5e37..f318dcb 100644
--- a/services/surfaceflinger/Scheduler/VSyncReactor.h
+++ b/services/surfaceflinger/Scheduler/VSyncReactor.h
@@ -61,6 +61,8 @@
     void reset() final;
 
 private:
+    void startPeriodTransition(nsecs_t newPeriod) REQUIRES(mMutex);
+    void endPeriodTransition() REQUIRES(mMutex);
     bool periodChangeDetected(nsecs_t vsync_timestamp) REQUIRES(mMutex);
 
     std::unique_ptr<Clock> const mClock;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 8c1d168..65d02ad 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -163,21 +163,6 @@
     return false;
 }
 
-ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
-    switch (rotation) {
-        case ISurfaceComposer::eRotateNone:
-            return ui::Transform::ROT_0;
-        case ISurfaceComposer::eRotate90:
-            return ui::Transform::ROT_90;
-        case ISurfaceComposer::eRotate180:
-            return ui::Transform::ROT_180;
-        case ISurfaceComposer::eRotate270:
-            return ui::Transform::ROT_270;
-    }
-    ALOGE("Invalid rotation passed to captureScreen(): %d\n", rotation);
-    return ui::Transform::ROT_0;
-}
-
 #pragma clang diagnostic pop
 
 class ConditionalLock {
@@ -215,7 +200,7 @@
 bool SurfaceFlinger::useVrFlinger;
 int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
 bool SurfaceFlinger::hasWideColorDisplay;
-int SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
+ui::Rotation SurfaceFlinger::internalDisplayOrientation = ui::ROTATION_0;
 bool SurfaceFlinger::useColorManagement;
 bool SurfaceFlinger::useContextPriority;
 Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
@@ -298,23 +283,21 @@
 
     useContextPriority = use_context_priority(true);
 
-    auto tmpPrimaryDisplayOrientation = primary_display_orientation(
-            SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_0);
-    switch (tmpPrimaryDisplayOrientation) {
-        case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_90:
-            SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation90;
+    using Values = SurfaceFlingerProperties::primary_display_orientation_values;
+    switch (primary_display_orientation(Values::ORIENTATION_0)) {
+        case Values::ORIENTATION_0:
             break;
-        case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_180:
-            SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation180;
+        case Values::ORIENTATION_90:
+            internalDisplayOrientation = ui::ROTATION_90;
             break;
-        case SurfaceFlingerProperties::primary_display_orientation_values::ORIENTATION_270:
-            SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientation270;
+        case Values::ORIENTATION_180:
+            internalDisplayOrientation = ui::ROTATION_180;
             break;
-        default:
-            SurfaceFlinger::primaryDisplayOrientation = DisplayState::eOrientationDefault;
+        case Values::ORIENTATION_270:
+            internalDisplayOrientation = ui::ROTATION_270;
             break;
     }
-    ALOGV("Primary Display Orientation is set to %2d.", SurfaceFlinger::primaryDisplayOrientation);
+    ALOGV("Internal Display Orientation: %s", toCString(internalDisplayOrientation));
 
     mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
 
@@ -789,9 +772,8 @@
             }
             info.density = density;
 
-            // TODO: this needs to go away (currently needed only by webkit)
             const auto display = getDefaultDisplayDeviceLocked();
-            info.orientation = display ? display->getOrientation() : 0;
+            info.orientation = display->getOrientation();
 
             // This is for screenrecord
             const Rect viewport = display->getViewport();
@@ -804,7 +786,6 @@
             // TODO: where should this value come from?
             static const int TV_DENSITY = 213;
             info.density = TV_DENSITY / 160.0f;
-            info.orientation = 0;
 
             const auto display = getDisplayDeviceLocked(displayToken);
             info.layerStack = display->getLayerStack();
@@ -835,7 +816,8 @@
         info.secure = true;
 
         if (displayId == getInternalDisplayIdLocked() &&
-            primaryDisplayOrientation & DisplayState::eOrientationSwapMask) {
+            (internalDisplayOrientation == ui::ROTATION_90 ||
+             internalDisplayOrientation == ui::ROTATION_270)) {
             std::swap(info.w, info.h);
         }
 
@@ -1570,6 +1552,11 @@
     mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline);
 }
 
+void SurfaceFlinger::onSeamlessPossible(int32_t /*sequenceId*/, hwc2_display_t /*display*/) {
+    // TODO(b/142753666): use constraints when calling to setActiveConfigWithConstrains and
+    // use this callback to know when to retry in case of SEAMLESS_NOT_POSSIBLE.
+}
+
 void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
     Mutex::Autolock lock(mStateLock);
     if (sequenceId != getBE().mComposerSequenceId) {
@@ -2279,8 +2266,8 @@
         nativeWindow->setSwapInterval(nativeWindow.get(), 0);
     }
 
-    creationArgs.displayInstallOrientation =
-            isInternalDisplay ? primaryDisplayOrientation : DisplayState::eOrientationDefault;
+    creationArgs.physicalOrientation =
+            isInternalDisplay ? internalDisplayOrientation : ui::ROTATION_0;
 
     // virtual displays are always considered enabled
     creationArgs.initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
@@ -3817,7 +3804,7 @@
              DisplayState::eLayerStackChanged;
     d.token = token;
     d.layerStack = 0;
-    d.orientation = DisplayState::eOrientationDefault;
+    d.orientation = ui::ROTATION_0;
     d.frame.makeInvalid();
     d.viewport.makeInvalid();
     d.width = 0;
@@ -4270,12 +4257,9 @@
 
 LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
     LayersProto layersProto;
-    mDrawingState.traverseInZOrder([&](Layer* layer) {
-        LayerProto* layerProto = layersProto.add_layers();
-        layer->writeToProtoDrawingState(layerProto, traceFlags);
-        layer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
-    });
-
+    for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
+        layer->writeToProto(layersProto, traceFlags);
+    }
     return layersProto;
 }
 
@@ -4299,15 +4283,7 @@
                                                 traceFlags);
         layerProto->set_parent(offscreenRootLayerId);
 
-        // Add children
-        offscreenLayer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-            if (layer == offscreenLayer) {
-                return;
-            }
-            LayerProto* childProto = layersProto.add_layers();
-            layer->writeToProtoDrawingState(childProto, traceFlags);
-            layer->writeToProtoCommonState(childProto, LayerVector::StateSet::Drawing, traceFlags);
-        });
+        offscreenLayer->writeToProto(layersProto, traceFlags);
     }
 }
 
@@ -4426,8 +4402,8 @@
     if (const auto display = getDefaultDisplayDeviceLocked()) {
         display->getCompositionDisplay()->getState().undefinedRegion.dump(result,
                                                                           "undefinedRegion");
-        StringAppendF(&result, "  orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
-                      display->isPoweredOn());
+        StringAppendF(&result, "  orientation=%s, isPoweredOn=%d\n",
+                      toCString(display->getOrientation()), display->isPoweredOn());
     }
     StringAppendF(&result,
                   "  transaction-flags         : %08x\n"
@@ -5004,17 +4980,19 @@
 
 status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
                                        sp<GraphicBuffer>* outBuffer, bool& outCapturedSecureLayers,
-                                       const Dataspace reqDataspace,
-                                       const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
-                                       uint32_t reqWidth, uint32_t reqHeight,
-                                       bool useIdentityTransform,
-                                       ISurfaceComposer::Rotation rotation,
-                                       bool captureSecureLayers) {
+                                       Dataspace reqDataspace, ui::PixelFormat reqPixelFormat,
+                                       const Rect& sourceCrop, uint32_t reqWidth,
+                                       uint32_t reqHeight, bool useIdentityTransform,
+                                       ui::Rotation rotation, bool captureSecureLayers) {
     ATRACE_CALL();
 
     if (!displayToken) return BAD_VALUE;
 
-    auto renderAreaRotation = fromSurfaceComposerRotation(rotation);
+    auto renderAreaRotation = ui::Transform::toRotationFlags(rotation);
+    if (renderAreaRotation == ui::Transform::ROT_INVALID) {
+        ALOGE("%s: Invalid rotation: %s", __FUNCTION__, toCString(rotation));
+        renderAreaRotation = ui::Transform::ROT_0;
+    }
 
     sp<DisplayDevice> display;
     {
@@ -5076,7 +5054,7 @@
     sp<DisplayDevice> display;
     uint32_t width;
     uint32_t height;
-    ui::Transform::orientation_flags captureOrientation;
+    ui::Transform::RotationFlags captureOrientation;
     {
         Mutex::Autolock _l(mStateLock);
         display = getDisplayByIdOrLayerStack(displayOrLayerStack);
@@ -5087,12 +5065,25 @@
         width = uint32_t(display->getViewport().width());
         height = uint32_t(display->getViewport().height());
 
-        captureOrientation = fromSurfaceComposerRotation(
-                static_cast<ISurfaceComposer::Rotation>(display->getOrientation()));
-        if (captureOrientation == ui::Transform::orientation_flags::ROT_90) {
-            captureOrientation = ui::Transform::orientation_flags::ROT_270;
-        } else if (captureOrientation == ui::Transform::orientation_flags::ROT_270) {
-            captureOrientation = ui::Transform::orientation_flags::ROT_90;
+        const auto orientation = display->getOrientation();
+        captureOrientation = ui::Transform::toRotationFlags(orientation);
+
+        switch (captureOrientation) {
+            case ui::Transform::ROT_90:
+                captureOrientation = ui::Transform::ROT_270;
+                break;
+
+            case ui::Transform::ROT_270:
+                captureOrientation = ui::Transform::ROT_90;
+                break;
+
+            case ui::Transform::ROT_INVALID:
+                ALOGE("%s: Invalid orientation: %s", __FUNCTION__, toCString(orientation));
+                captureOrientation = ui::Transform::ROT_0;
+                break;
+
+            default:
+                break;
         }
         *outDataspace =
                 pickDataspaceFromColorMode(display->getCompositionDisplay()->getState().colorMode);
@@ -5140,7 +5131,7 @@
         }
         bool isSecure() const override { return false; }
         bool needsFiltering() const override { return mNeedsFiltering; }
-        const sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
+        sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
         Rect getSourceCrop() const override {
             if (mCrop.isEmpty()) {
                 return getBounds();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2f84b13..723e332 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -229,7 +229,7 @@
     // found on devices with wide color gamut (e.g. Display-P3) display.
     static bool hasWideColorDisplay;
 
-    static int primaryDisplayOrientation;
+    static ui::Rotation internalDisplayOrientation;
 
     // Indicate if device wants color management on its display.
     static bool useColorManagement;
@@ -415,10 +415,10 @@
             ISurfaceComposer::ConfigChanged configChanged =
                     ISurfaceComposer::eConfigChangedSuppress) override;
     status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
-            bool& outCapturedSecureLayers, const ui::Dataspace reqDataspace,
-            const ui::PixelFormat reqPixelFormat, Rect sourceCrop,
-            uint32_t reqWidth, uint32_t reqHeight,
-            bool useIdentityTransform, ISurfaceComposer::Rotation rotation, bool captureSecureLayers) override;
+                           bool& outCapturedSecureLayers, ui::Dataspace reqDataspace,
+                           ui::PixelFormat reqPixelFormat, const Rect& sourceCrop,
+                           uint32_t reqWidth, uint32_t reqHeight, bool useIdentityTransform,
+                           ui::Rotation rotation, bool captureSecureLayers) override;
     status_t captureScreen(uint64_t displayOrLayerStack, ui::Dataspace* outDataspace,
                            sp<GraphicBuffer>* outBuffer) override;
     status_t captureLayers(
@@ -505,6 +505,7 @@
     void onVsyncPeriodTimingChangedReceived(
             int32_t sequenceId, hwc2_display_t display,
             const hwc_vsync_period_change_timeline_t& updatedTimeline) override;
+    void onSeamlessPossible(int32_t sequenceId, hwc2_display_t display) override;
 
     /* ------------------------------------------------------------------------
      * ISchedulerCallback
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 5e8910a..8e0462a 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -137,8 +137,8 @@
     addDisplaySurfaceLocked(transaction, display.sequenceId, display.surface);
     addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack);
     addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height);
-    addDisplayProjectionLocked(transaction, display.sequenceId, display.orientation,
-            display.viewport, display.frame);
+    addDisplayProjectionLocked(transaction, display.sequenceId, toRotationInt(display.orientation),
+                               display.viewport, display.frame);
 }
 
 status_t SurfaceInterceptor::writeProtoFileLocked() {
@@ -467,8 +467,8 @@
         addDisplaySizeLocked(transaction, sequenceId, state.width, state.height);
     }
     if (state.what & DisplayState::eDisplayProjectionChanged) {
-        addDisplayProjectionLocked(transaction, sequenceId, state.orientation, state.viewport,
-                state.frame);
+        addDisplayProjectionLocked(transaction, sequenceId, toRotationInt(state.orientation),
+                                   state.viewport, state.frame);
     }
 }
 
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 1895777..a5fabf2 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -618,6 +618,8 @@
     mTimeStats.clientCompositionFrames = 0;
     mTimeStats.displayOnTime = 0;
     mTimeStats.presentToPresent.hist.clear();
+    mTimeStats.frameDuration.hist.clear();
+    mTimeStats.renderEngineTiming.hist.clear();
     mTimeStats.refreshRateStats.clear();
     mPowerTime.prevTime = systemTime();
     mGlobalRecord.prevPresentTime = 0;
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 4c1baaf..1475889 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -310,8 +310,8 @@
                     // we get pointers that compare unequal in the SF process.
                     interface_cast<ITransactionCompletedListener>(listenerStats.listener)
                             ->onTransactionCompleted(listenerStats);
-                    listener->unlinkToDeath(mDeathRecipient);
                     if (transactionStatsDeque.empty()) {
+                        listener->unlinkToDeath(mDeathRecipient);
                         completedTransactionsItr =
                                 mCompletedTransactions.erase(completedTransactionsItr);
                     } else {
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 23df1bb..41ecafa 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -102,6 +102,8 @@
   // layer or set by a parent layer.
   float shadow_radius = 49;
   ColorTransformProto color_transform = 50;
+
+  bool is_relative_of = 51;
 }
 
 message PositionProto {
diff --git a/services/surfaceflinger/tests/Credentials_test.cpp b/services/surfaceflinger/tests/Credentials_test.cpp
index b1bb7fd..f618873 100644
--- a/services/surfaceflinger/tests/Credentials_test.cpp
+++ b/services/surfaceflinger/tests/Credentials_test.cpp
@@ -23,7 +23,6 @@
 namespace {
 const String8 DISPLAY_NAME("Credentials Display Test");
 const String8 SURFACE_NAME("Test Surface Name");
-const uint32_t ROTATION = 0;
 const float FRAME_SCALE = 1.0f;
 } // namespace
 
@@ -262,7 +261,7 @@
         sp<GraphicBuffer> outBuffer;
         return ScreenshotClient::capture(display, ui::Dataspace::V0_SRGB,
                                          ui::PixelFormat::RGBA_8888, Rect(), 0 /*reqWidth*/,
-                                         0 /*reqHeight*/, false, ROTATION, &outBuffer);
+                                         0 /*reqHeight*/, false, ui::ROTATION_0, &outBuffer);
     };
     ASSERT_NO_FATAL_FAILURE(checkWithPrivileges<status_t>(condition, NO_ERROR, PERMISSION_DENIED));
 }
diff --git a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
index 627de7a..92698f0 100644
--- a/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerRenderTypeTransaction_test.cpp
@@ -189,12 +189,12 @@
 }
 
 TEST_P(LayerRenderTypeTransactionTest, CreateLayer_BufferState) {
-    uint32_t transformHint = ui::Transform::orientation_flags::ROT_INVALID;
+    uint32_t transformHint = ui::Transform::ROT_INVALID;
     sp<SurfaceControl> layer;
     ASSERT_NO_FATAL_FAILURE(layer = createLayer("test", 32, 32,
                                                 ISurfaceComposerClient::eFXSurfaceBufferState,
                                                 /*parent*/ nullptr, &transformHint));
-    ASSERT_NE(ui::Transform::orientation_flags::ROT_INVALID, transformHint);
+    ASSERT_NE(ui::Transform::ROT_INVALID, transformHint);
 }
 
 void LayerRenderTypeTransactionTest::setRelativeZBasicHelper(uint32_t layerType) {
diff --git a/services/surfaceflinger/tests/LayerTransaction_test.cpp b/services/surfaceflinger/tests/LayerTransaction_test.cpp
index 35c51e1..7816c66 100644
--- a/services/surfaceflinger/tests/LayerTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTransaction_test.cpp
@@ -53,7 +53,7 @@
     ASSERT_EQ(NO_ERROR,
               composer->captureScreen(mDisplay, &outBuffer, outCapturedSecureLayers,
                                       ui::Dataspace::V0_SRGB, ui::PixelFormat::RGBA_8888, Rect(), 0,
-                                      0, false, ISurfaceComposer::eRotateNone, true));
+                                      0, false, ui::ROTATION_0, true));
     ASSERT_EQ(true, outCapturedSecureLayers);
     ScreenCapture sc(outBuffer);
     sc.expectColor(Rect(0, 0, 32, 32), Color::RED);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 76e8171..55c3ab8 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -2040,8 +2040,8 @@
 TEST_F(HandleTransactionLockedTest, processesDisplayTransformChanges) {
     using Case = NonHwcVirtualDisplayCase;
 
-    constexpr int oldTransform = 0;
-    constexpr int newTransform = 2;
+    constexpr ui::Rotation oldTransform = ui::ROTATION_0;
+    constexpr ui::Rotation newTransform = ui::ROTATION_180;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2414,7 +2414,7 @@
 
 TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingIfProjectionDidNotChange) {
     using Case = SimplePrimaryDisplayCase;
-    constexpr int initialOrientation = 180;
+    constexpr ui::Rotation initialOrientation = ui::ROTATION_180;
     const Rect initialFrame = {1, 2, 3, 4};
     const Rect initialViewport = {5, 6, 7, 8};
 
@@ -2458,8 +2458,8 @@
 
 TEST_F(DisplayTransactionTest, setDisplayStateLockedRequestsUpdateIfOrientationChanged) {
     using Case = SimplePrimaryDisplayCase;
-    constexpr int initialOrientation = 90;
-    constexpr int desiredOrientation = 180;
+    constexpr ui::Rotation initialOrientation = ui::ROTATION_90;
+    constexpr ui::Rotation desiredOrientation = ui::ROTATION_180;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -2721,7 +2721,7 @@
     // The layer stack state should be set to zero
     EXPECT_EQ(0u, primaryDisplayState.layerStack);
     // The orientation state should be set to zero
-    EXPECT_EQ(0, primaryDisplayState.orientation);
+    EXPECT_EQ(ui::ROTATION_0, primaryDisplayState.orientation);
 
     // The frame state should be set to INVALID
     EXPECT_EQ(Rect::INVALID_RECT, primaryDisplayState.frame);
diff --git a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
index d95252b..f055fe7 100644
--- a/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
+++ b/services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp
@@ -29,8 +29,8 @@
 
     LayerHistoryTest() { mFlinger.resetScheduler(mScheduler); }
 
-    LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
-    const LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
+    impl::LayerHistory& history() { return *mScheduler->mutableLayerHistory(); }
+    const impl::LayerHistory& history() const { return *mScheduler->mutableLayerHistory(); }
 
     size_t layerCount() const { return mScheduler->layerHistorySize(); }
     size_t activeLayerCount() const NO_THREAD_SAFETY_ANALYSIS { return history().mActiveLayersEnd; }
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index fa095aa..a67c24c 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -30,14 +30,14 @@
 public:
     explicit TestableScheduler(const scheduler::RefreshRateConfigs& configs)
           : Scheduler([](bool) {}, configs, *this) {
-        mLayerHistory.emplace();
+        mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
     }
 
     TestableScheduler(std::unique_ptr<DispSync> primaryDispSync,
                       std::unique_ptr<EventControlThread> eventControlThread,
                       const scheduler::RefreshRateConfigs& configs)
           : Scheduler(std::move(primaryDispSync), std::move(eventControlThread), configs, *this) {
-        mLayerHistory.emplace();
+        mLayerHistory = std::make_unique<scheduler::impl::LayerHistory>();
     }
 
     // Used to inject mock event thread.
@@ -46,7 +46,7 @@
     }
 
     size_t layerHistorySize() const NO_THREAD_SAFETY_ANALYSIS {
-        return mLayerHistory->mLayerInfos.size();
+        return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get())->mLayerInfos.size();
     }
 
     /* ------------------------------------------------------------------------
@@ -57,7 +57,9 @@
     auto& mutableEventControlThread() { return mEventControlThread; }
     auto& mutablePrimaryDispSync() { return mPrimaryDispSync; }
     auto& mutableHWVsyncAvailable() { return mHWVsyncAvailable; }
-    auto& mutableLayerHistory() { return mLayerHistory; }
+    auto mutableLayerHistory() {
+        return static_cast<scheduler::impl::LayerHistory*>(mLayerHistory.get());
+    }
 
     ~TestableScheduler() {
         // All these pointer and container clears help ensure that GMock does
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index b5245e2..9728c80 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -371,7 +371,6 @@
      */
 
     auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
-    auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
     auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
 
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
diff --git a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
index 68e4c58..3e808c0 100644
--- a/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TimeStatsTest.cpp
@@ -562,6 +562,16 @@
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementMissedFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->incrementClientCompositionFrames());
     ASSERT_NO_FATAL_FAILURE(mTimeStats->setPowerMode(HWC_POWER_MODE_NORMAL));
+
+    using namespace std::chrono_literals;
+    mTimeStats
+            ->recordFrameDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(3ms).count(),
+                                  std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                          .count());
+    mTimeStats->recordRenderEngineDuration(std::chrono::duration_cast<std::chrono::nanoseconds>(4ms)
+                                                   .count(),
+                                           std::chrono::duration_cast<std::chrono::nanoseconds>(6ms)
+                                                   .count());
     ASSERT_NO_FATAL_FAILURE(
             mTimeStats->setPresentFenceGlobal(std::make_shared<FenceTime>(1000000)));
     ASSERT_NO_FATAL_FAILURE(
@@ -578,6 +588,8 @@
     EXPECT_EQ(0, globalProto.missed_frames());
     EXPECT_EQ(0, globalProto.client_composition_frames());
     EXPECT_EQ(0, globalProto.present_to_present_size());
+    EXPECT_EQ(0, globalProto.frame_duration_size());
+    EXPECT_EQ(0, globalProto.render_engine_timing_size());
     EXPECT_EQ(0, globalProto.stats_size());
 }
 
diff --git a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
index 72f8bb9..4df20af 100644
--- a/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncReactorTest.cpp
@@ -292,6 +292,46 @@
     EXPECT_TRUE(periodFlushed);
 }
 
+TEST_F(VSyncReactorTest, changingPeriodBackAbortsConfirmationProcess) {
+    nsecs_t sampleTime = 0;
+    nsecs_t const newPeriod = 5000;
+    mReactor.setPeriod(newPeriod);
+    bool periodFlushed = true;
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+
+    mReactor.setPeriod(period);
+    EXPECT_FALSE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, changingToAThirdPeriodWillWaitForLastPeriod) {
+    nsecs_t sampleTime = 0;
+    nsecs_t const secondPeriod = 5000;
+    nsecs_t const thirdPeriod = 2000;
+
+    mReactor.setPeriod(secondPeriod);
+    bool periodFlushed = true;
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += period, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    mReactor.setPeriod(thirdPeriod);
+    EXPECT_TRUE(mReactor.addResyncSample(sampleTime += secondPeriod, &periodFlushed));
+    EXPECT_FALSE(periodFlushed);
+    EXPECT_FALSE(mReactor.addResyncSample(sampleTime += thirdPeriod, &periodFlushed));
+    EXPECT_TRUE(periodFlushed);
+}
+
+TEST_F(VSyncReactorTest, presentFenceAdditionDoesNotInterruptConfirmationProcess) {
+    nsecs_t const newPeriod = 5000;
+    mReactor.setPeriod(newPeriod);
+    EXPECT_TRUE(mReactor.addPresentFence(generateSignalledFenceWithTime(0)));
+}
+
 TEST_F(VSyncReactorTest, setPeriodCalledFirstTwoEventsNewPeriod) {
     nsecs_t const newPeriod = 5000;
     EXPECT_CALL(*mMockTracker, setPeriod(_)).Times(0);
diff --git a/services/vr/hardware_composer/impl/vr_composer_client.cpp b/services/vr/hardware_composer/impl/vr_composer_client.cpp
index 36f6b32..dd1603d 100644
--- a/services/vr/hardware_composer/impl/vr_composer_client.cpp
+++ b/services/vr/hardware_composer/impl/vr_composer_client.cpp
@@ -73,7 +73,7 @@
 
   auto err = mVrHal.setLayerInfo(mCurrentDisplay, mCurrentLayer, read(), read());
   if (err != Error::NONE) {
-    mWriter.setError(getCommandLoc(), err);
+    mWriter->setError(getCommandLoc(), err);
   }
 
   return true;
@@ -86,7 +86,7 @@
 
   auto err = mVrHal.setClientTargetMetadata(mCurrentDisplay, readBufferMetadata());
   if (err != Error::NONE)
-    mWriter.setError(getCommandLoc(), err);
+    mWriter->setError(getCommandLoc(), err);
 
   return true;
 }
@@ -99,7 +99,7 @@
   auto err = mVrHal.setLayerBufferMetadata(mCurrentDisplay, mCurrentLayer,
                                            readBufferMetadata());
   if (err != Error::NONE)
-    mWriter.setError(getCommandLoc(), err);
+    mWriter->setError(getCommandLoc(), err);
 
   return true;
 }