Merge "FocusRequest token can be nullable" into tm-dev
diff --git a/data/etc/android.hardware.telephony.euicc.mep.xml b/data/etc/android.hardware.telephony.euicc.mep.xml
new file mode 100644
index 0000000..f958e4b
--- /dev/null
+++ b/data/etc/android.hardware.telephony.euicc.mep.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- Feature for devices with an eUICC supporting MEP(Multiple enabled profiles) -->
+<permissions>
+    <feature name="android.hardware.telephony.euicc" />
+    <feature name="android.hardware.telephony.euicc.mep" />
+</permissions>
\ No newline at end of file
diff --git a/libs/binder/rust/src/lib.rs b/libs/binder/rust/src/lib.rs
index 1d7de98..dbfb1c2 100644
--- a/libs/binder/rust/src/lib.rs
+++ b/libs/binder/rust/src/lib.rs
@@ -114,8 +114,8 @@
 };
 pub use parcel::{ParcelFileDescriptor, Parcelable, ParcelableHolder};
 pub use proxy::{
-    get_interface, get_service, wait_for_interface, wait_for_service, DeathRecipient, SpIBinder,
-    WpIBinder,
+    get_declared_instances, get_interface, get_service, is_declared, wait_for_interface,
+    wait_for_service, DeathRecipient, SpIBinder, WpIBinder,
 };
 pub use state::{ProcessState, ThreadState};
 
diff --git a/libs/binder/rust/src/proxy.rs b/libs/binder/rust/src/proxy.rs
index 12bfde7..e3e4730 100644
--- a/libs/binder/rust/src/proxy.rs
+++ b/libs/binder/rust/src/proxy.rs
@@ -28,9 +28,10 @@
 
 use std::cmp::Ordering;
 use std::convert::TryInto;
-use std::ffi::{c_void, CString};
+use std::ffi::{c_void, CStr, CString};
 use std::fmt;
 use std::mem;
+use std::os::raw::c_char;
 use std::os::unix::io::AsRawFd;
 use std::ptr;
 use std::sync::Arc;
@@ -778,6 +779,61 @@
     }
 }
 
+/// Check if a service is declared (e.g. in a VINTF manifest)
+pub fn is_declared(interface: &str) -> Result<bool> {
+    let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+
+    unsafe {
+        // Safety: `interface` is a valid null-terminated C-style string and is
+        // only borrowed for the lifetime of the call. The `interface` local
+        // outlives this call as it lives for the function scope.
+        Ok(sys::AServiceManager_isDeclared(interface.as_ptr()))
+    }
+}
+
+/// Retrieve all declared instances for a particular interface
+///
+/// For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo'
+/// is passed here, then ["foo"] would be returned.
+pub fn get_declared_instances(interface: &str) -> Result<Vec<String>> {
+    unsafe extern "C" fn callback(instance: *const c_char, opaque: *mut c_void) {
+        // Safety: opaque was a mutable pointer created below from a Vec of
+        // CString, and outlives this callback. The null handling here is just
+        // to avoid the possibility of unwinding across C code if this crate is
+        // ever compiled with panic=unwind.
+        if let Some(instances) = opaque.cast::<Vec<CString>>().as_mut() {
+            // Safety: instance is a valid null-terminated C string with a
+            // lifetime at least as long as this function, and we immediately
+            // copy it into an owned CString.
+            instances.push(CStr::from_ptr(instance).to_owned());
+        } else {
+            eprintln!("Opaque pointer was null in get_declared_instances callback!");
+        }
+    }
+
+    let interface = CString::new(interface).or(Err(StatusCode::UNEXPECTED_NULL))?;
+    let mut instances: Vec<CString> = vec![];
+    unsafe {
+        // Safety: `interface` and `instances` are borrowed for the length of
+        // this call and both outlive the call. `interface` is guaranteed to be
+        // a valid null-terminated C-style string.
+        sys::AServiceManager_forEachDeclaredInstance(
+            interface.as_ptr(),
+            &mut instances as *mut _ as *mut c_void,
+            Some(callback),
+        );
+    }
+
+    instances
+        .into_iter()
+        .map(CString::into_string)
+        .collect::<std::result::Result<Vec<String>, _>>()
+        .map_err(|e| {
+            eprintln!("An interface instance name was not a valid UTF-8 string: {}", e);
+            StatusCode::BAD_VALUE
+        })
+}
+
 /// # Safety
 ///
 /// `SpIBinder` guarantees that `binder` always contains a valid pointer to an
diff --git a/libs/binder/rust/tests/integration.rs b/libs/binder/rust/tests/integration.rs
index 50daf1c..7c5afde 100644
--- a/libs/binder/rust/tests/integration.rs
+++ b/libs/binder/rust/tests/integration.rs
@@ -484,6 +484,21 @@
     }
 
     #[test]
+    fn get_declared_instances() {
+        // At the time of writing this test, there is no good VINTF interface
+        // guaranteed to be on all devices. Cuttlefish has light, so this will
+        // generally test things.
+        let has_lights = binder::is_declared("android.hardware.light.ILights/default")
+            .expect("Could not check for declared interface");
+
+        let instances = binder::get_declared_instances("android.hardware.light.ILights")
+            .expect("Could not get declared instances");
+
+        let expected_defaults = if has_lights { 1 } else { 0 };
+        assert_eq!(expected_defaults, instances.iter().filter(|i| i.as_str() == "default").count());
+    }
+
+    #[test]
     fn trivial_client() {
         let service_name = "trivial_client_test";
         let _process = ScopedServiceProcess::new(service_name);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index ebe112b..c7984bd 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -78,7 +78,7 @@
     virtual void applyChangedTypesToLayers(const ChangedTypes&);
     virtual void applyDisplayRequests(const DisplayRequests&);
     virtual void applyLayerRequestsToLayers(const LayerRequests&);
-    virtual void applyClientTargetRequests(const ClientTargetProperty&, float whitePointNits);
+    virtual void applyClientTargetRequests(const ClientTargetProperty&, float brightness);
 
     // Internal
     virtual void setConfiguration(const compositionengine::DisplayCreationArgs&);
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
index 7521324..196af70 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/DumpHelpers.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <cstdint>
+#include <optional>
 #include <string>
 #include <type_traits>
 
@@ -63,4 +64,13 @@
 void dumpVal(std::string& out, const char* name, const mat4&);
 void dumpVal(std::string& out, const char* name, const StretchEffect&);
 
+template <typename T>
+void dumpVal(std::string& out, const char* name, std::optional<T> value) {
+    if (value.has_value()) {
+        return dumpVal(out, name, *value);
+    } else {
+        return dumpVal(out, name, "nullopt");
+    }
+}
+
 } // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index cc7c257..66dd825 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -130,8 +130,8 @@
     // SDR white point
     float sdrWhitePointNits{-1.f};
 
-    // White point of the client target
-    float clientTargetWhitePointNits{-1.f};
+    // Brightness of the client target, normalized to display brightness
+    float clientTargetBrightness{1.f};
 
     // Display brightness that will take effect this frame.
     // This is slightly distinct from nits, in that nits cannot be passed to hw composer.
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index a3188f3..6390025 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -266,8 +266,7 @@
         applyChangedTypesToLayers(changes->changedTypes);
         applyDisplayRequests(changes->displayRequests);
         applyLayerRequestsToLayers(changes->layerRequests);
-        applyClientTargetRequests(changes->clientTargetProperty,
-                                  changes->clientTargetWhitePointNits);
+        applyClientTargetRequests(changes->clientTargetProperty, changes->clientTargetBrightness);
     }
 
     // Determine what type of composition we are doing from the final state
@@ -343,13 +342,13 @@
 }
 
 void Display::applyClientTargetRequests(const ClientTargetProperty& clientTargetProperty,
-                                        float whitePointNits) {
+                                        float brightness) {
     if (clientTargetProperty.dataspace == ui::Dataspace::UNKNOWN) {
         return;
     }
 
     editState().dataspace = clientTargetProperty.dataspace;
-    editState().clientTargetWhitePointNits = whitePointNits;
+    editState().clientTargetBrightness = brightness;
     getRenderSurface()->setBufferDataspace(clientTargetProperty.dataspace);
     getRenderSurface()->setBufferPixelFormat(clientTargetProperty.pixelFormat);
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index e036252..ff332eb 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -1076,7 +1076,8 @@
             : mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
     clientCompositionDisplay.maxLuminance =
             mDisplayColorProfile->getHdrCapabilities().getDesiredMaxLuminance();
-    clientCompositionDisplay.targetLuminanceNits = outputState.clientTargetWhitePointNits;
+    clientCompositionDisplay.targetLuminanceNits =
+            outputState.clientTargetBrightness * outputState.displayBrightnessNits;
 
     // Compute the global color transform matrix.
     clientCompositionDisplay.colorTransform = outputState.colorTransformMatrix;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index acc9216..482250a 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -52,6 +52,10 @@
     dumpVal(out, "dataspace", toString(dataspace), dataspace);
     dumpVal(out, "colorTransformMatrix", colorTransformMatrix);
     dumpVal(out, "target dataspace", toString(targetDataspace), targetDataspace);
+    dumpVal(out, "displayBrightnessNits", displayBrightnessNits);
+    dumpVal(out, "sdrWhitePointNits", sdrWhitePointNits);
+    dumpVal(out, "clientTargetBrightness", clientTargetBrightness);
+    dumpVal(out, "displayBrightness", displayBrightness);
 
     out.append("\n");
 }
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
index cfa740e..6749427 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayerCompositionState.cpp
@@ -67,6 +67,8 @@
     dumpVal(out, "sourceCrop", sourceCrop);
     dumpVal(out, "bufferTransform", toString(bufferTransform), bufferTransform);
     dumpVal(out, "dataspace", toString(dataspace), dataspace);
+    dumpVal(out, "whitePointNits", whitePointNits);
+    dumpVal(out, "dimmingRatio", dimmingRatio);
     dumpVal(out, "override buffer", overrideInfo.buffer.get());
     dumpVal(out, "override acquire fence", overrideInfo.acquireFence.get());
     dumpVal(out, "override display frame", overrideInfo.displayFrame);
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index 44d34a3..cd03235 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -839,7 +839,7 @@
 
     auto& state = mDisplay->getState();
     EXPECT_EQ(clientTargetProperty.dataspace, state.dataspace);
-    EXPECT_EQ(kWhitePointNits, state.clientTargetWhitePointNits);
+    EXPECT_EQ(kWhitePointNits, state.clientTargetBrightness);
 }
 
 /*
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index cab4b8d..c2521b2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -3067,7 +3067,7 @@
         mOutput.mState.usesDeviceComposition = false;
         mOutput.mState.reusedClientComposition = false;
         mOutput.mState.flipClientTarget = false;
-        mOutput.mState.clientTargetWhitePointNits = kClientTargetLuminanceNits;
+        mOutput.mState.clientTargetBrightness = kClientTargetBrightness;
 
         EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
         EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
@@ -3103,8 +3103,9 @@
     static constexpr float kDefaultAvgLuminance = 0.7f;
     static constexpr float kDefaultMinLuminance = 0.1f;
     static constexpr float kUnknownLuminance = -1.f;
-    static constexpr float kDisplayLuminance = 80.f;
+    static constexpr float kDisplayLuminance = 400.f;
     static constexpr float kClientTargetLuminanceNits = 200.f;
+    static constexpr float kClientTargetBrightness = 0.5f;
 
     static const Rect kDefaultOutputFrame;
     static const Rect kDefaultOutputViewport;
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
index 8d67954..80e2d99 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.cpp
@@ -20,6 +20,7 @@
 
 #include "AidlComposerHal.h"
 
+#include <android-base/file.h>
 #include <android/binder_ibinder_platform.h>
 #include <android/binder_manager.h>
 #include <log/log.h>
@@ -115,7 +116,7 @@
 AidlPerFrameMetadataBlob translate(IComposerClient::PerFrameMetadataBlob x) {
     AidlPerFrameMetadataBlob blob;
     blob.key = translate<AidlPerFrameMetadataKey>(x.key),
-    std::copy(blob.blob.begin(), blob.blob.end(), x.blob.begin());
+    std::copy(x.blob.begin(), x.blob.end(), std::inserter(blob.blob, blob.blob.end()));
     return blob;
 }
 
@@ -262,13 +263,27 @@
 }
 
 std::string AidlComposer::dumpDebugInfo() {
-    std::string info;
-    const auto status = mAidlComposer->dumpDebugInfo(&info);
-    if (!status.isOk()) {
-        ALOGE("dumpDebugInfo failed %s", status.getDescription().c_str());
+    int pipefds[2];
+    int result = pipe(pipefds);
+    if (result < 0) {
+        ALOGE("dumpDebugInfo: pipe failed: %s", strerror(errno));
         return {};
     }
-    return info;
+
+    std::string str;
+    const auto status = mAidlComposer->dump(pipefds[1], /*args*/ nullptr, /*numArgs*/ 0);
+    // Close the write-end of the pipe to make sure that when reading from the
+    // read-end we will get eof instead of blocking forever
+    close(pipefds[1]);
+
+    if (status == STATUS_OK) {
+        base::ReadFdToString(pipefds[0], &str);
+    } else {
+        ALOGE("dumpDebugInfo: dump failed: %d", status);
+    }
+
+    close(pipefds[0]);
+    return str;
 }
 
 void AidlComposer::registerCallback(HWC2::ComposerCallback& callback) {
@@ -1054,11 +1069,11 @@
 
 Error AidlComposer::getClientTargetProperty(
         Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
-        float* whitePointNits) {
+        float* outBrightness) {
     const auto property = mReader.takeClientTargetProperty(translate<int64_t>(display));
     *outClientTargetProperty =
             translate<IComposerClient::ClientTargetProperty>(property.clientTargetProperty);
-    *whitePointNits = property.whitePointNits;
+    *outBrightness = property.brightness;
     return Error::NONE;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
index 724c6c9..80ca8da 100644
--- a/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/AidlComposerHal.h
@@ -209,7 +209,7 @@
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
     Error getClientTargetProperty(Display display,
                                   IComposerClient::ClientTargetProperty* outClientTargetProperty,
-                                  float* outClientTargetWhitePointNits) override;
+                                  float* outBrightness) override;
 
     // AIDL Composer HAL
     Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 06aaa11..23886d4 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -261,7 +261,7 @@
 
     virtual Error getClientTargetProperty(
             Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
-            float* outWhitePointNits) = 0;
+            float* outBrightness) = 0;
 
     // AIDL Composer
     virtual Error setLayerBrightness(Display display, Layer layer, float brightness) = 0;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 6a3162e..ed6e4b0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -479,13 +479,12 @@
     RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
 
     DeviceRequestedChanges::ClientTargetProperty clientTargetProperty;
-    float clientTargetWhitePointNits;
-    error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &clientTargetWhitePointNits);
+    float brightness = 1.f;
+    error = hwcDisplay->getClientTargetProperty(&clientTargetProperty, &brightness);
 
     outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
                                                std::move(layerRequests),
-                                               std::move(clientTargetProperty),
-                                               clientTargetWhitePointNits});
+                                               std::move(clientTargetProperty), brightness});
     error = hwcDisplay->acceptChanges();
     RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 916c4b7..5b2e265 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -86,7 +86,7 @@
         DisplayRequests displayRequests;
         LayerRequests layerRequests;
         ClientTargetProperty clientTargetProperty;
-        float clientTargetWhitePointNits;
+        float clientTargetBrightness;
     };
 
     struct HWCDisplayMode {
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
index 95d7b58..f735bba 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.cpp
@@ -1297,9 +1297,9 @@
 
 Error HidlComposer::getClientTargetProperty(
         Display display, IComposerClient::ClientTargetProperty* outClientTargetProperty,
-        float* outWhitePointNits) {
+        float* outBrightness) {
     mReader.takeClientTargetProperty(display, outClientTargetProperty);
-    *outWhitePointNits = -1.f;
+    *outBrightness = 1.f;
     return Error::NONE;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
index 71ae8b4..c2b60cb 100644
--- a/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/HidlComposerHal.h
@@ -318,7 +318,7 @@
             std::vector<IComposerClient::LayerGenericMetadataKey>* outKeys) override;
     Error getClientTargetProperty(Display display,
                                   IComposerClient::ClientTargetProperty* outClientTargetProperty,
-                                  float* outWhitePointNits) override;
+                                  float* outBrightness) override;
 
     // AIDL Composer HAL
     Error setLayerBrightness(Display display, Layer layer, float brightness) override;
diff --git a/services/surfaceflinger/FlagManager.cpp b/services/surfaceflinger/FlagManager.cpp
index e09a192..bd3cf74 100644
--- a/services/surfaceflinger/FlagManager.cpp
+++ b/services/surfaceflinger/FlagManager.cpp
@@ -101,7 +101,6 @@
 }
 
 bool FlagManager::use_skia_tracing() const {
-    ALOGD("use_skia_tracing ?");
     std::optional<bool> sysPropVal =
             doParse<bool>(base::GetProperty(PROPERTY_SKIA_ATRACE_ENABLED, "").c_str());
     return getValue("SkiaTracingFeature__use_skia_tracing", sysPropVal, false);
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index eeeaac1..15e30b3 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -202,24 +202,24 @@
     }
 
     if (layer.vote == LayerVoteType::ExplicitExact) {
-        const int divider = getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate);
+        const int divisor = getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate);
         if (mSupportsFrameRateOverrideByContent) {
             // Since we support frame rate override, allow refresh rates which are
             // multiples of the layer's request, as those apps would be throttled
             // down to run at the desired refresh rate.
-            return divider > 0;
+            return divisor > 0;
         }
 
-        return divider == 1;
+        return divisor == 1;
     }
 
-    // If the layer frame rate is a divider of the refresh rate it should score
+    // If the layer frame rate is a divisor of the refresh rate it should score
     // the highest score.
-    if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
+    if (getFrameRateDivisor(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
         return 1.0f * seamlessness;
     }
 
-    // The layer frame rate is not a divider of the refresh rate,
+    // The layer frame rate is not a divisor of the refresh rate,
     // there is a small penalty attached to the score to favor the frame rates
     // the exactly matches the display refresh rate or a multiple.
     constexpr float kNonExactMatchingPenalty = 0.95f;
@@ -543,11 +543,11 @@
             }
         }
 
-        // We just care about the refresh rates which are a divider of the
+        // We just care about the refresh rates which are a divisor of the
         // display refresh rate
         auto iter =
                 std::remove_if(scores.begin(), scores.end(), [&](const RefreshRateScore& score) {
-                    return getFrameRateDivider(displayFrameRate, score.refreshRate->getFps()) == 0;
+                    return getFrameRateDivisor(displayFrameRate, score.refreshRate->getFps()) == 0;
                 });
         scores.erase(iter, scores.end());
 
@@ -723,7 +723,7 @@
     if (mConfig.enableFrameRateOverride) {
         for (const auto& mode1 : sortedModes) {
             for (const auto& mode2 : sortedModes) {
-                if (getFrameRateDivider(mode1->getFps(), mode2->getFps()) >= 2) {
+                if (getFrameRateDivisor(mode1->getFps(), mode2->getFps()) >= 2) {
                     mSupportsFrameRateOverrideByContent = true;
                     break;
                 }
@@ -915,7 +915,7 @@
     return RefreshRateConfigs::KernelIdleTimerAction::TurnOn;
 }
 
-int RefreshRateConfigs::getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate) {
+int RefreshRateConfigs::getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate) {
     // This calculation needs to be in sync with the java code
     // in DisplayManagerService.getDisplayInfoForFrameRateOverride
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index f5b97c2..14583e3 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -316,10 +316,10 @@
 
     bool supportsFrameRateOverrideByContent() const { return mSupportsFrameRateOverrideByContent; }
 
-    // Return the display refresh rate divider to match the layer
+    // Return the display refresh rate divisor to match the layer
     // frame rate, or 0 if the display refresh rate is not a multiple of the
     // layer refresh rate.
-    static int getFrameRateDivider(Fps displayFrameRate, Fps layerFrameRate);
+    static int getFrameRateDivisor(Fps displayFrameRate, Fps layerFrameRate);
 
     // Returns if the provided frame rates have a ratio t*1000/1001 or t*1001/1000
     // for an integer t.
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 82ff2fa..1fa455a 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -173,15 +173,15 @@
             return basePeriod;
         }
 
-        const auto divider =
-                scheduler::RefreshRateConfigs::getFrameRateDivider(refreshRateConfigs
+        const auto divisor =
+                scheduler::RefreshRateConfigs::getFrameRateDivisor(refreshRateConfigs
                                                                            ->getCurrentRefreshRate()
                                                                            .getFps(),
                                                                    *frameRate);
-        if (divider <= 1) {
+        if (divisor <= 1) {
             return basePeriod;
         }
-        return basePeriod * divider;
+        return basePeriod * divisor;
     };
 }
 
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index 61d2fb7..77782e9 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -256,7 +256,7 @@
 
 /*
  * Returns whether a given vsync timestamp is in phase with a frame rate.
- * If the frame rate is not a divider of the refresh rate, it is always considered in phase.
+ * If the frame rate is not a divisor of the refresh rate, it is always considered in phase.
  * For example, if the vsync timestamps are (16.6,33.3,50.0,66.6):
  * isVSyncInPhase(16.6, 30) = true
  * isVSyncInPhase(33.3, 30) = false
@@ -271,42 +271,42 @@
     };
 
     std::lock_guard lock(mMutex);
-    const auto divider =
-            RefreshRateConfigs::getFrameRateDivider(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
-    if (divider <= 1 || timePoint == 0) {
+    const auto divisor =
+            RefreshRateConfigs::getFrameRateDivisor(Fps::fromPeriodNsecs(mIdealPeriod), frameRate);
+    if (divisor <= 1 || timePoint == 0) {
         return true;
     }
 
     const nsecs_t period = mRateMap[mIdealPeriod].slope;
     const nsecs_t justBeforeTimePoint = timePoint - period / 2;
-    const nsecs_t dividedPeriod = mIdealPeriod / divider;
+    const nsecs_t dividedPeriod = mIdealPeriod / divisor;
 
-    // If this is the first time we have asked about this divider with the
+    // If this is the first time we have asked about this divisor with the
     // current vsync period, it is considered in phase and we store the closest
     // vsync timestamp
-    const auto knownTimestampIter = mRateDividerKnownTimestampMap.find(dividedPeriod);
-    if (knownTimestampIter == mRateDividerKnownTimestampMap.end()) {
+    const auto knownTimestampIter = mRateDivisorKnownTimestampMap.find(dividedPeriod);
+    if (knownTimestampIter == mRateDivisorKnownTimestampMap.end()) {
         const auto vsync = nextAnticipatedVSyncTimeFromLocked(justBeforeTimePoint);
-        mRateDividerKnownTimestampMap[dividedPeriod] = vsync;
+        mRateDivisorKnownTimestampMap[dividedPeriod] = vsync;
         return true;
     }
 
-    // Find the next N vsync timestamp where N is the divider.
+    // Find the next N vsync timestamp where N is the divisor.
     // One of these vsyncs will be in phase. We return the one which is
     // the most aligned with the last known in phase vsync
-    std::vector<VsyncError> vsyncs(static_cast<size_t>(divider));
+    std::vector<VsyncError> vsyncs(static_cast<size_t>(divisor));
     const nsecs_t knownVsync = knownTimestampIter->second;
     nsecs_t point = justBeforeTimePoint;
-    for (size_t i = 0; i < divider; i++) {
+    for (size_t i = 0; i < divisor; i++) {
         const nsecs_t vsync = nextAnticipatedVSyncTimeFromLocked(point);
-        const auto numPeriods = static_cast<float>(vsync - knownVsync) / (period * divider);
+        const auto numPeriods = static_cast<float>(vsync - knownVsync) / (period * divisor);
         const auto error = std::abs(std::round(numPeriods) - numPeriods);
         vsyncs[i] = {vsync, error};
         point = vsync + 1;
     }
 
     const auto minVsyncError = std::min_element(vsyncs.begin(), vsyncs.end());
-    mRateDividerKnownTimestampMap[dividedPeriod] = minVsyncError->vsyncTimestamp;
+    mRateDivisorKnownTimestampMap[dividedPeriod] = minVsyncError->vsyncTimestamp;
     return std::abs(minVsyncError->vsyncTimestamp - timePoint) < period / 2;
 }
 
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.h b/services/surfaceflinger/Scheduler/VSyncPredictor.h
index cfaf7d6..3181102 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.h
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.h
@@ -96,7 +96,7 @@
     std::unordered_map<nsecs_t, Model> mutable mRateMap GUARDED_BY(mMutex);
 
     // Map between the divided vsync period and the last known vsync timestamp
-    std::unordered_map<nsecs_t, nsecs_t> mutable mRateDividerKnownTimestampMap GUARDED_BY(mMutex);
+    std::unordered_map<nsecs_t, nsecs_t> mutable mRateDivisorKnownTimestampMap GUARDED_BY(mMutex);
 
     size_t mLastTimestampIndex GUARDED_BY(mMutex) = 0;
     std::vector<nsecs_t> mTimestamps GUARDED_BY(mMutex);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 59c07b6..2cd34e9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -507,7 +507,7 @@
         return LatchUnsignaledConfig::Always;
     }
 
-    if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, true)) {
+    if (base::GetBoolProperty("debug.sf.auto_latch_unsignaled"s, false)) {
         return LatchUnsignaledConfig::AutoSingleLayer;
     }
 
@@ -2344,16 +2344,19 @@
 
 void SurfaceFlinger::setCompositorTimingSnapped(const DisplayStatInfo& stats,
                                                 nsecs_t compositeToPresentLatency) {
+    // Avoid division by 0 by defaulting to 60Hz
+    const auto vsyncPeriod = stats.vsyncPeriod ?: (60_Hz).getPeriodNsecs();
+
     // Integer division and modulo round toward 0 not -inf, so we need to
     // treat negative and positive offsets differently.
     nsecs_t idealLatency = (mVsyncConfiguration->getCurrentConfigs().late.sfOffset > 0)
-            ? (stats.vsyncPeriod -
-               (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % stats.vsyncPeriod))
-            : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % stats.vsyncPeriod);
+            ? (vsyncPeriod -
+               (mVsyncConfiguration->getCurrentConfigs().late.sfOffset % vsyncPeriod))
+            : ((-mVsyncConfiguration->getCurrentConfigs().late.sfOffset) % vsyncPeriod);
 
     // Just in case mVsyncConfiguration->getCurrentConfigs().late.sf == -vsyncInterval.
     if (idealLatency <= 0) {
-        idealLatency = stats.vsyncPeriod;
+        idealLatency = vsyncPeriod;
     }
 
     // Snap the latency to a value that removes scheduling jitter from the
@@ -2362,16 +2365,14 @@
     // something (such as user input) to an accurate diasplay time.
     // Snapping also allows an app to precisely calculate
     // mVsyncConfiguration->getCurrentConfigs().late.sf with (presentLatency % interval).
-    const nsecs_t bias = stats.vsyncPeriod / 2;
-    const int64_t extraVsyncs = (stats.vsyncPeriod) > 0 ?
-        ((compositeToPresentLatency - idealLatency + bias) / stats.vsyncPeriod) :
-        0;
+    const nsecs_t bias = vsyncPeriod / 2;
+    const int64_t extraVsyncs = ((compositeToPresentLatency - idealLatency + bias) / vsyncPeriod);
     const nsecs_t snappedCompositeToPresentLatency =
-            (extraVsyncs > 0) ? idealLatency + (extraVsyncs * stats.vsyncPeriod) : idealLatency;
+            (extraVsyncs > 0) ? idealLatency + (extraVsyncs * vsyncPeriod) : idealLatency;
 
     std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
     getBE().mCompositorTiming.deadline = stats.vsyncTime - idealLatency;
-    getBE().mCompositorTiming.interval = stats.vsyncPeriod;
+    getBE().mCompositorTiming.interval = vsyncPeriod;
     getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
@@ -5341,7 +5342,7 @@
     colorizer.reset(result);
     const bool hwcDisabled = mDebugDisableHWC || mDebugFlashDelay;
     StringAppendF(&result, "  h/w composer %s\n", hwcDisabled ? "disabled" : "enabled");
-    getHwComposer().dump(result);
+    dumpHwc(result);
 
     /*
      * Dump gralloc state
diff --git a/services/surfaceflinger/Tracing/tools/Android.bp b/services/surfaceflinger/Tracing/tools/Android.bp
new file mode 100644
index 0000000..114f1eb
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/Android.bp
@@ -0,0 +1,46 @@
+// Copyright (C) 2022 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.
+
+cc_binary {
+    name: "layertracegenerator",
+    defaults: [
+        "libsurfaceflinger_mocks_defaults",
+        "surfaceflinger_defaults",
+        "skia_renderengine_deps",
+    ],
+    srcs: [
+        ":libsurfaceflinger_sources",
+        ":libsurfaceflinger_mock_sources",
+        ":layertracegenerator_sources",
+        "main.cpp",
+    ],
+    static_libs: [
+        "libgtest",
+    ],
+    header_libs: [
+        "libsurfaceflinger_mocks_headers",
+    ],
+}
+
+filegroup {
+    name: "layertracegenerator_sources",
+    srcs: [
+        "LayerTraceGenerator.cpp",
+    ],
+}
+
+cc_library_headers {
+    name: "layertracegenerator_headers",
+    export_include_dirs: ["."],
+}
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
new file mode 100644
index 0000000..947fdce
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTraceGenerator"
+
+#include <TestableSurfaceFlinger.h>
+#include <Tracing/TransactionProtoParser.h>
+#include <binder/IPCThreadState.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <gui/LayerState.h>
+#include <log/log.h>
+#include <mock/MockEventThread.h>
+#include <renderengine/ExternalTexture.h>
+#include <renderengine/mock/FakeExternalTexture.h>
+#include <renderengine/mock/RenderEngine.h>
+#include <utils/String16.h>
+#include <string>
+
+#include "LayerTraceGenerator.h"
+
+namespace android {
+
+class Factory final : public surfaceflinger::Factory {
+public:
+    ~Factory() = default;
+
+    std::unique_ptr<HWComposer> createHWComposer(const std::string&) override { return nullptr; }
+
+    std::unique_ptr<scheduler::VsyncConfiguration> createVsyncConfiguration(
+            Fps /*currentRefreshRate*/) override {
+        return std::make_unique<scheduler::FakePhaseOffsets>();
+    }
+
+    sp<SurfaceInterceptor> createSurfaceInterceptor() override {
+        return new android::impl::SurfaceInterceptor();
+    }
+
+    sp<StartPropertySetThread> createStartPropertySetThread(
+            bool /* timestampPropertyValue */) override {
+        return nullptr;
+    }
+
+    sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs& /* creationArgs */) override {
+        return nullptr;
+    }
+
+    sp<GraphicBuffer> createGraphicBuffer(uint32_t /* width */, uint32_t /* height */,
+                                          PixelFormat /* format */, uint32_t /* layerCount */,
+                                          uint64_t /* usage */,
+                                          std::string /* requestorName */) override {
+        return nullptr;
+    }
+
+    void createBufferQueue(sp<IGraphicBufferProducer>* /* outProducer */,
+                           sp<IGraphicBufferConsumer>* /* outConsumer */,
+                           bool /* consumerIsSurfaceFlinger */) override {}
+
+    sp<IGraphicBufferProducer> createMonitoredProducer(
+            const sp<IGraphicBufferProducer>& /* producer */,
+            const sp<SurfaceFlinger>& /* flinger */, const wp<Layer>& /* layer */) override {
+        return nullptr;
+    }
+
+    sp<BufferLayerConsumer> createBufferLayerConsumer(
+            const sp<IGraphicBufferConsumer>& /* consumer */,
+            renderengine::RenderEngine& /* renderEngine */, uint32_t /* textureName */,
+            Layer* /* layer */) override {
+        return nullptr;
+    }
+
+    std::unique_ptr<surfaceflinger::NativeWindowSurface> createNativeWindowSurface(
+            const sp<IGraphicBufferProducer>& /* producer */) override {
+        return nullptr;
+    }
+
+    std::unique_ptr<compositionengine::CompositionEngine> createCompositionEngine() override {
+        return compositionengine::impl::createCompositionEngine();
+    }
+
+    sp<ContainerLayer> createContainerLayer(const LayerCreationArgs& args) {
+        return sp<ContainerLayer>::make(args);
+    }
+
+    sp<BufferStateLayer> createBufferStateLayer(const LayerCreationArgs& args) {
+        return new BufferStateLayer(args);
+    }
+
+    sp<EffectLayer> createEffectLayer(const LayerCreationArgs& args) {
+        return new EffectLayer(args);
+    }
+
+    sp<BufferQueueLayer> createBufferQueueLayer(const LayerCreationArgs&) override {
+        return nullptr;
+    }
+
+    std::unique_ptr<FrameTracer> createFrameTracer() override {
+        return std::make_unique<testing::NiceMock<mock::FrameTracer>>();
+    }
+
+    std::unique_ptr<frametimeline::FrameTimeline> createFrameTimeline(
+            std::shared_ptr<TimeStats> timeStats, pid_t surfaceFlingerPid = 0) override {
+        return std::make_unique<testing::NiceMock<mock::FrameTimeline>>(timeStats,
+                                                                        surfaceFlingerPid);
+    }
+};
+
+class MockSurfaceFlinger : public SurfaceFlinger {
+public:
+    MockSurfaceFlinger(Factory& factory)
+          : SurfaceFlinger(factory, SurfaceFlinger::SkipInitialization) {}
+    std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData(
+            const BufferData& bufferData, const char* /* layerName */) const override {
+        return std::make_shared<renderengine::mock::FakeExternalTexture>(bufferData.getWidth(),
+                                                                         bufferData.getHeight(),
+                                                                         bufferData.getId(),
+                                                                         bufferData
+                                                                                 .getPixelFormat(),
+                                                                         bufferData.getUsage());
+    };
+
+    // b/220017192 migrate from transact codes to ISurfaceComposer apis
+    void setLayerTracingFlags(int32_t flags) {
+        Parcel data;
+        Parcel reply;
+        data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+        data.writeInt32(flags);
+        transact(1033, data, &reply, 0 /* flags */);
+    }
+
+    void startLayerTracing(int64_t traceStartTime) {
+        Parcel data;
+        Parcel reply;
+        data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+        data.writeInt32(1);
+        data.writeInt64(traceStartTime);
+        transact(1025, data, &reply, 0 /* flags */);
+    }
+
+    void stopLayerTracing(const char* tracePath) {
+        Parcel data;
+        Parcel reply;
+        data.writeInterfaceToken(String16("android.ui.ISurfaceComposer"));
+        data.writeInt32(2);
+        data.writeCString(tracePath);
+        transact(1025, data, &reply, 0 /* flags */);
+    }
+};
+
+class TraceGenFlingerDataMapper : public TransactionProtoParser::FlingerDataMapper {
+public:
+    std::unordered_map<int32_t /*layerId*/, sp<IBinder> /* handle */> mLayerHandles;
+    sp<IBinder> getLayerHandle(int32_t layerId) const override {
+        if (layerId == -1) {
+            ALOGE("Error: Called with layer=%d", layerId);
+            return nullptr;
+        }
+        auto it = mLayerHandles.find(layerId);
+        if (it == mLayerHandles.end()) {
+            ALOGE("Error: Could not find handle for layer=%d", layerId);
+            return nullptr;
+        }
+        return it->second;
+    }
+};
+
+bool LayerTraceGenerator::generate(const proto::TransactionTraceFile& traceFile,
+                                   const char* outputLayersTracePath) {
+    if (traceFile.entry_size() == 0) {
+        return false;
+    }
+
+    Factory mFactory;
+    sp<MockSurfaceFlinger> flinger = new MockSurfaceFlinger(mFactory);
+    TestableSurfaceFlinger mFlinger(flinger);
+    mFlinger.setupRenderEngine(
+            std::make_unique<testing::NiceMock<renderengine::mock::RenderEngine>>());
+    mock::VsyncController* mVsyncController = new testing::NiceMock<mock::VsyncController>();
+    mock::VSyncTracker* mVSyncTracker = new testing::NiceMock<mock::VSyncTracker>();
+    mock::EventThread* mEventThread = new testing::NiceMock<mock::EventThread>();
+    mock::EventThread* mSFEventThread = new testing::NiceMock<mock::EventThread>();
+    mFlinger.setupScheduler(std::unique_ptr<scheduler::VsyncController>(mVsyncController),
+                            std::unique_ptr<scheduler::VSyncTracker>(mVSyncTracker),
+                            std::unique_ptr<EventThread>(mEventThread),
+                            std::unique_ptr<EventThread>(mSFEventThread),
+                            TestableSurfaceFlinger::SchedulerCallbackImpl::kNoOp,
+                            TestableSurfaceFlinger::kOneDisplayMode, true /* useNiceMock */);
+
+    Hwc2::mock::Composer* mComposer = new testing::NiceMock<Hwc2::mock::Composer>();
+    mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+    mFlinger.mutableMaxRenderTargetSize() = 16384;
+
+    flinger->setLayerTracingFlags(LayerTracing::TRACE_BUFFERS | LayerTracing::TRACE_INPUT |
+                                  LayerTracing::TRACE_BUFFERS);
+    flinger->startLayerTracing(traceFile.entry(0).elapsed_realtime_nanos());
+    std::unique_ptr<TraceGenFlingerDataMapper> mapper =
+            std::make_unique<TraceGenFlingerDataMapper>();
+    TraceGenFlingerDataMapper* dataMapper = mapper.get();
+    TransactionProtoParser parser(std::move(mapper));
+
+    nsecs_t frameTime;
+    int64_t vsyncId;
+    ALOGD("Generating %d transactions...", traceFile.entry_size());
+    for (int i = 0; i < traceFile.entry_size(); i++) {
+        proto::TransactionTraceEntry entry = traceFile.entry(i);
+        ALOGV("    Entry %04d/%04d for time=%" PRId64 " vsyncid=%" PRId64
+              " layers +%d -%d transactions=%d",
+              i, traceFile.entry_size(), entry.elapsed_realtime_nanos(), entry.vsync_id(),
+              entry.added_layers_size(), entry.removed_layers_size(), entry.transactions_size());
+
+        for (int j = 0; j < entry.added_layers_size(); j++) {
+            // create layers
+            TracingLayerCreationArgs tracingArgs;
+            parser.fromProto(entry.added_layers(j), tracingArgs);
+
+            sp<IBinder> outHandle;
+            int32_t outLayerId;
+            LayerCreationArgs args(mFlinger.flinger(), nullptr /* client */, tracingArgs.name,
+                                   tracingArgs.flags, LayerMetadata());
+            args.sequence = std::make_optional<int32_t>(tracingArgs.layerId);
+
+            if (tracingArgs.mirrorFromId == -1) {
+                sp<IBinder> parentHandle = nullptr;
+                if ((tracingArgs.parentId != -1) &&
+                    (dataMapper->mLayerHandles.find(tracingArgs.parentId) ==
+                     dataMapper->mLayerHandles.end())) {
+                    args.addToRoot = false;
+                } else {
+                    parentHandle = dataMapper->getLayerHandle(tracingArgs.parentId);
+                }
+                mFlinger.createLayer(args, &outHandle, parentHandle, &outLayerId,
+                                     nullptr /* parentLayer */, nullptr /* outTransformHint */);
+            } else {
+                sp<IBinder> mirrorFromHandle = dataMapper->getLayerHandle(tracingArgs.mirrorFromId);
+                mFlinger.mirrorLayer(args, mirrorFromHandle, &outHandle, &outLayerId);
+            }
+            LOG_ALWAYS_FATAL_IF(outLayerId != tracingArgs.layerId,
+                                "Could not create layer expected:%d actual:%d", tracingArgs.layerId,
+                                outLayerId);
+            dataMapper->mLayerHandles[tracingArgs.layerId] = outHandle;
+        }
+
+        for (int j = 0; j < entry.transactions_size(); j++) {
+            // apply transactions
+            TransactionState transaction = parser.fromProto(entry.transactions(j));
+            mFlinger.setTransactionState(transaction.frameTimelineInfo, transaction.states,
+                                         transaction.displays, transaction.flags,
+                                         transaction.applyToken, transaction.inputWindowCommands,
+                                         transaction.desiredPresentTime,
+                                         transaction.isAutoTimestamp, {},
+                                         transaction.hasListenerCallbacks,
+                                         transaction.listenerCallbacks, transaction.id);
+        }
+
+        for (int j = 0; j < entry.removed_layer_handles_size(); j++) {
+            dataMapper->mLayerHandles.erase(entry.removed_layer_handles(j));
+        }
+
+        frameTime = entry.elapsed_realtime_nanos();
+        vsyncId = entry.vsync_id();
+        mFlinger.commit(frameTime, vsyncId);
+    }
+
+    flinger->stopLayerTracing(outputLayersTracePath);
+    ALOGD("End of generating trace file. File written to %s", outputLayersTracePath);
+    dataMapper->mLayerHandles.clear();
+    return true;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
new file mode 100644
index 0000000..ee1ea6c
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2022 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 <Tracing/TransactionTracing.h>
+
+namespace android {
+class LayerTraceGenerator {
+public:
+    bool generate(const proto::TransactionTraceFile&, const char* outputLayersTracePath);
+};
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Tracing/tools/main.cpp b/services/surfaceflinger/Tracing/tools/main.cpp
new file mode 100644
index 0000000..f3cf42d
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/main.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2022 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LayerTraceGenerator"
+
+#include <fstream>
+#include <iostream>
+#include <string>
+
+#include "LayerTraceGenerator.h"
+
+using namespace android;
+
+int main(int argc, char** argv) {
+    if (argc > 3) {
+        std::cout << "Usage: " << argv[0]
+                  << " [transaction-trace-path] [output-layers-trace-path]\n";
+        return -1;
+    }
+
+    const char* transactionTracePath =
+            (argc > 1) ? argv[1] : "/data/misc/wmtrace/transactions_trace.winscope";
+    std::cout << "Parsing " << transactionTracePath << "\n";
+    std::fstream input(transactionTracePath, std::ios::in | std::ios::binary);
+    if (!input) {
+        std::cout << "Error: Could not open " << transactionTracePath;
+        return -1;
+    }
+
+    proto::TransactionTraceFile transactionTraceFile;
+    if (!transactionTraceFile.ParseFromIstream(&input)) {
+        std::cout << "Error: Failed to parse " << transactionTracePath;
+        return -1;
+    }
+
+    const char* outputLayersTracePath =
+            (argc == 3) ? argv[2] : "/data/misc/wmtrace/layers_trace.winscope";
+    ;
+    ALOGD("Generating %s...", outputLayersTracePath);
+    std::cout << "Generating " << outputLayersTracePath << "\n";
+    if (!LayerTraceGenerator().generate(transactionTraceFile, outputLayersTracePath)) {
+        std::cout << "Error: Failed to generate layers trace " << outputLayersTracePath;
+        return -1;
+    }
+    return 0;
+}
\ No newline at end of file
diff --git a/services/surfaceflinger/Tracing/tools/readme.md b/services/surfaceflinger/Tracing/tools/readme.md
new file mode 100644
index 0000000..143c14f
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/readme.md
@@ -0,0 +1,13 @@
+### LayerTraceGenerator ###
+
+Generates layer traces from transaction traces. The tool is a custom
+surface flinger build that mocks out everything else apart from the
+front end logic. Transaction traces are written when the transaction
+is applied, along wth a timestamp and vsync id. The transactions
+are parsed from proto and applied to recreate the layer state. The
+result is then written as a layer trace.
+
+Usage:
+1. build and push to device
+2. run ./layertracegenerator [transaction-trace-path] [output-layers-trace-path]
+
diff --git a/services/surfaceflinger/Tracing/tools/run.sh b/services/surfaceflinger/Tracing/tools/run.sh
new file mode 100644
index 0000000..baa93f1
--- /dev/null
+++ b/services/surfaceflinger/Tracing/tools/run.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env bash
+
+set -ex
+
+# Build, push and run layertracegenerator
+$ANDROID_BUILD_TOP/build/soong/soong_ui.bash --make-mode layertracegenerator
+adb wait-for-device && adb push $OUT/system/bin/layertracegenerator /data/layertracegenerator
+echo "Writing transaction trace to file"
+adb shell service call SurfaceFlinger 1041 i32 0
+adb shell /data/layertracegenerator
+adb pull /data/misc/wmtrace/layers_trace.winscope
\ No newline at end of file
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 09ffb02..d504155 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -357,7 +357,7 @@
                                                            mFdp.ConsumeFloatingPoint<float>()),
                                                    Fps::fromValue(
                                                            mFdp.ConsumeFloatingPoint<float>()));
-    RefreshRateConfigs::getFrameRateDivider(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
+    RefreshRateConfigs::getFrameRateDivisor(Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
                                             Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()));
 
     android::mock::TimeStats timeStats;
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 1db5e61..58cd7ba 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -42,6 +42,7 @@
 cc_test {
     name: "libsurfaceflinger_unittest",
     defaults: [
+        "libsurfaceflinger_mocks_defaults",
         "skia_renderengine_deps",
         "surfaceflinger_defaults",
     ],
@@ -122,6 +123,10 @@
         "VSyncReactorTest.cpp",
         "VsyncConfigurationTest.cpp",
     ],
+}
+
+cc_defaults {
+    name: "libsurfaceflinger_mocks_defaults",
     static_libs: [
         "android.hardware.common-V2-ndk",
         "android.hardware.common.fmq-V1-ndk",
@@ -193,3 +198,8 @@
         "libsurfaceflinger_headers",
     ],
 }
+
+cc_library_headers {
+    name: "libsurfaceflinger_mocks_headers",
+    export_include_dirs: ["."],
+}
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 9143d61..97f3747 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -1873,37 +1873,37 @@
     EXPECT_EQ(KernelIdleTimerAction::TurnOff, configs.getIdleTimerAction());
 }
 
-TEST_F(RefreshRateConfigsTest, getFrameRateDivider) {
+TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) {
     RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
 
     const auto frameRate = 30_Hz;
     Fps displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId60);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId72);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId90);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId120);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, frameRate));
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
 
     configs.setCurrentModeId(kModeId90);
     displayRefreshRate = configs.getCurrentRefreshRate().getFps();
-    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivider(displayRefreshRate, 22.5_Hz));
+    EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz));
 
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 25_Hz));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(24_Hz, 23.976_Hz));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(30_Hz, 29.97_Hz));
-    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivider(60_Hz, 59.94_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 23.976_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(30_Hz, 29.97_Hz));
+    EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(60_Hz, 59.94_Hz));
 }
 
 TEST_F(RefreshRateConfigsTest, isFractionalPairOrMultiple) {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 67e47e7..d83b9bb 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -177,8 +177,10 @@
 public:
     using HotplugEvent = SurfaceFlinger::HotplugEvent;
 
-    TestableSurfaceFlinger()
-          : mFlinger(sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization)) {
+    TestableSurfaceFlinger(sp<SurfaceFlinger> flinger = nullptr) : mFlinger(flinger) {
+        if (!mFlinger) {
+            mFlinger = sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
+        }
         mFlinger->mAnimationTransactionTimeout = ms2ns(10);
     }
 
@@ -219,7 +221,8 @@
                         std::unique_ptr<EventThread> appEventThread,
                         std::unique_ptr<EventThread> sfEventThread,
                         SchedulerCallbackImpl callbackImpl = SchedulerCallbackImpl::kNoOp,
-                        DisplayModesVariant modesVariant = kOneDisplayMode) {
+                        DisplayModesVariant modesVariant = kOneDisplayMode,
+                        bool useNiceMock = false) {
         RefreshRateConfigsPtr configs;
         if (std::holds_alternative<RefreshRateConfigsPtr>(modesVariant)) {
             configs = std::move(std::get<RefreshRateConfigsPtr>(modesVariant));
@@ -256,9 +259,17 @@
                 ? static_cast<Callback&>(mNoOpSchedulerCallback)
                 : static_cast<Callback&>(mSchedulerCallback);
 
-        mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
-                                                      std::move(vsyncTracker), std::move(configs),
-                                                      callback);
+        if (useNiceMock) {
+            mScheduler =
+                    new testing::NiceMock<scheduler::TestableScheduler>(std::move(vsyncController),
+                                                                        std::move(vsyncTracker),
+                                                                        std::move(configs),
+                                                                        callback);
+        } else {
+            mScheduler = new scheduler::TestableScheduler(std::move(vsyncController),
+                                                          std::move(vsyncTracker),
+                                                          std::move(configs), callback);
+        }
 
         mFlinger->mAppConnectionHandle = mScheduler->createConnection(std::move(appEventThread));
         mFlinger->mSfConnectionHandle = mScheduler->createConnection(std::move(sfEventThread));
@@ -455,6 +466,23 @@
         mFlinger->onActiveDisplayChangedLocked(activeDisplay);
     }
 
+    auto commit(nsecs_t frameTime, int64_t vsyncId) {
+        const nsecs_t expectedVsyncTime = frameTime + 10'000'000;
+        mFlinger->commit(frameTime, vsyncId, expectedVsyncTime);
+    }
+
+    auto createLayer(LayerCreationArgs& args, sp<IBinder>* outHandle,
+                     const sp<IBinder>& parentHandle, int32_t* outLayerId,
+                     const sp<Layer>& parentLayer, uint32_t* outTransformHint) {
+        return mFlinger->createLayer(args, outHandle, parentHandle, outLayerId, parentLayer,
+                                     outTransformHint);
+    }
+
+    auto mirrorLayer(const LayerCreationArgs& args, const sp<IBinder>& mirrorFromHandle,
+                     sp<IBinder>* outHandle, int32_t* outLayerId) {
+        return mFlinger->mirrorLayer(args, mirrorFromHandle, outHandle, outLayerId);
+    }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -850,8 +878,7 @@
 
 private:
     surfaceflinger::test::Factory mFactory;
-    sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(mFactory, SurfaceFlinger::SkipInitialization);
-
+    sp<SurfaceFlinger> mFlinger;
     scheduler::mock::SchedulerCallback mSchedulerCallback;
     scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;
     scheduler::TestableScheduler* mScheduler = nullptr;
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index 37ecd7c..74d2b7d 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -464,16 +464,16 @@
     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 100), Eq(mNow + mPeriod - bias));
     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow + 990), Eq(mNow + 2 * mPeriod - bias));
 
-    const auto maxDivider = 5;
+    const auto maxDivisor = 5;
     const auto maxPeriods = 15;
-    for (int divider = 1; divider < maxDivider; divider++) {
+    for (int divisor = 1; divisor < maxDivisor; divisor++) {
         for (int i = 0; i < maxPeriods; i++) {
-            const bool expectedInPhase = (i % divider) == 0;
+            const bool expectedInPhase = (i % divisor) == 0;
             EXPECT_THAT(expectedInPhase,
                         tracker.isVSyncInPhase(mNow + i * mPeriod - bias,
-                                               Fps::fromPeriodNsecs(divider * mPeriod)))
+                                               Fps::fromPeriodNsecs(divisor * mPeriod)))
                     << "vsync at " << mNow + (i + 1) * mPeriod - bias << " is "
-                    << (expectedInPhase ? "not " : "") << "in phase for divider " << divider;
+                    << (expectedInPhase ? "not " : "") << "in phase for divisor " << divisor;
         }
     }
 }