Merge "Increase injection timeout for InputFilterInjectionPolicyTest"
diff --git a/data/etc/input/Android.bp b/data/etc/input/Android.bp
index 90f3c6b..b662491 100644
--- a/data/etc/input/Android.bp
+++ b/data/etc/input/Android.bp
@@ -3,12 +3,21 @@
 }
 
 filegroup {
-    name: "motion_predictor_model.fb",
-    srcs: ["motion_predictor_model.fb"],
+    name: "motion_predictor_model",
+    srcs: [
+        "motion_predictor_model.tflite",
+        "motion_predictor_config.xml",
+    ],
 }
 
 prebuilt_etc {
     name: "motion_predictor_model_prebuilt",
     filename_from_src: true,
-    src: "motion_predictor_model.fb",
+    src: "motion_predictor_model.tflite",
+}
+
+prebuilt_etc {
+    name: "motion_predictor_model_config",
+    filename_from_src: true,
+    src: "motion_predictor_config.xml",
 }
diff --git a/data/etc/input/motion_predictor_config.xml b/data/etc/input/motion_predictor_config.xml
new file mode 100644
index 0000000..03dfd63
--- /dev/null
+++ b/data/etc/input/motion_predictor_config.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 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.
+-->
+<motion-predictor>
+  <!-- The time interval (ns) between the model's predictions. -->
+  <prediction-interval>4166666</prediction-interval>  <!-- 4.167 ms = ~240 Hz -->
+</motion-predictor>
+
diff --git a/data/etc/input/motion_predictor_model.fb b/data/etc/input/motion_predictor_model.tflite
similarity index 100%
rename from data/etc/input/motion_predictor_model.fb
rename to data/etc/input/motion_predictor_model.tflite
Binary files differ
diff --git a/include/input/PrintTools.h b/include/input/PrintTools.h
index 0ca6fa3..0e3fbb1 100644
--- a/include/input/PrintTools.h
+++ b/include/input/PrintTools.h
@@ -27,6 +27,9 @@
 
 template <size_t N>
 std::string bitsetToString(const std::bitset<N>& bitset) {
+    if (bitset.none()) {
+        return "<none>";
+    }
     return bitset.to_string();
 }
 
diff --git a/include/input/TfLiteMotionPredictor.h b/include/input/TfLiteMotionPredictor.h
index a340bd0..fbd6026 100644
--- a/include/input/TfLiteMotionPredictor.h
+++ b/include/input/TfLiteMotionPredictor.h
@@ -25,6 +25,7 @@
 
 #include <android-base/mapped_file.h>
 #include <input/RingBuffer.h>
+#include <utils/Timers.h>
 
 #include <tensorflow/lite/core/api/error_reporter.h>
 #include <tensorflow/lite/interpreter.h>
@@ -109,6 +110,9 @@
     // Returns the length of the model's output buffers.
     size_t outputLength() const;
 
+    // Returns the time interval between predictions.
+    nsecs_t predictionInterval() const { return mPredictionInterval; }
+
     // Executes the model.
     // Returns true if the model successfully executed and the output tensors can be read.
     bool invoke();
@@ -127,7 +131,8 @@
     std::span<const float> outputPressure() const;
 
 private:
-    explicit TfLiteMotionPredictorModel(std::unique_ptr<android::base::MappedFile> model);
+    explicit TfLiteMotionPredictorModel(std::unique_ptr<android::base::MappedFile> model,
+                                        nsecs_t predictionInterval);
 
     void allocateTensors();
     void attachInputTensors();
@@ -148,6 +153,8 @@
     std::unique_ptr<tflite::FlatBufferModel> mModel;
     std::unique_ptr<tflite::Interpreter> mInterpreter;
     tflite::SignatureRunner* mRunner = nullptr;
+
+    const nsecs_t mPredictionInterval = 0;
 };
 
 } // namespace android
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 582437f..b6b0cfb 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -399,45 +399,28 @@
         return false;
     }
 
-    return (mShouldUseAngle == YES) ? true : false;
+    return mShouldUseAngle;
 }
 
-void GraphicsEnv::updateShouldUseAngle() {
-    const char* ANGLE_PREFER_ANGLE = "angle";
-    const char* ANGLE_PREFER_NATIVE = "native";
-
-    mShouldUseAngle = NO;
-    if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
-        ALOGV("User set \"Developer Options\" to force the use of ANGLE");
-        mShouldUseAngle = YES;
-    } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
-        ALOGV("User set \"Developer Options\" to force the use of Native");
-    } else {
-        ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str());
-    }
-}
-
-void GraphicsEnv::setAngleInfo(const std::string& path, const std::string& packageName,
-                               const std::string& developerOptIn,
+void GraphicsEnv::setAngleInfo(const std::string& path, const bool useSystemAngle,
+                               const std::string& packageName,
                                const std::vector<std::string> eglFeatures) {
-    if (mShouldUseAngle != UNKNOWN) {
-        // We've already figured out an answer for this app, so just return.
-        ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", packageName.c_str(),
-              (mShouldUseAngle == YES) ? "true" : "false");
+    if (mShouldUseAngle) {
+        // ANGLE is already set up for this application process, even if the application
+        // needs to switch from apk to system or vice versa, the application process must
+        // be killed and relaunch so that the loader can properly load ANGLE again.
+        // The architecture does not support runtime switch between drivers, so just return.
+        ALOGE("ANGLE is already set for %s", packageName.c_str());
         return;
     }
 
     mAngleEglFeatures = std::move(eglFeatures);
-
     ALOGV("setting ANGLE path to '%s'", path.c_str());
-    mAnglePath = path;
+    mAnglePath = std::move(path);
     ALOGV("setting app package name to '%s'", packageName.c_str());
-    mPackageName = packageName;
-    ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
-    mAngleDeveloperOptIn = developerOptIn;
-
-    // Update the current status of whether we should use ANGLE or not
-    updateShouldUseAngle();
+    mPackageName = std::move(packageName);
+    mShouldUseAngle = true;
+    mUseSystemAngle = useSystemAngle;
 }
 
 void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace,
@@ -484,13 +467,15 @@
 }
 
 // Return true if all the required libraries from vndk and sphal namespace are
-// linked to the updatable gfx driver namespace correctly.
-bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
+// linked to the driver namespace correctly.
+bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace,
+                                            android_namespace_t* vndkNamespace,
+                                            const std::string& sharedSphalLibraries) {
     const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
     if (llndkLibraries.empty()) {
         return false;
     }
-    if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
+    if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) {
         ALOGE("Failed to link default namespace[%s]", dlerror());
         return false;
     }
@@ -499,12 +484,12 @@
     if (vndkspLibraries.empty()) {
         return false;
     }
-    if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
+    if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) {
         ALOGE("Failed to link vndk namespace[%s]", dlerror());
         return false;
     }
 
-    if (mSphalLibraries.empty()) {
+    if (sharedSphalLibraries.empty()) {
         return true;
     }
 
@@ -512,11 +497,11 @@
     auto sphalNamespace = android_get_exported_namespace("sphal");
     if (!sphalNamespace) {
         ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
-              mSphalLibraries.c_str());
+              sharedSphalLibraries.c_str());
         return false;
     }
 
-    if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
+    if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) {
         ALOGE("Failed to link sphal namespace[%s]", dlerror());
         return false;
     }
@@ -568,7 +553,7 @@
                                                 nullptr, // permitted_when_isolated_path
                                                 nullptr);
 
-    if (!linkDriverNamespaceLocked(vndkNamespace)) {
+    if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) {
         mDriverNamespace = nullptr;
     }
 
@@ -586,20 +571,48 @@
         return mAngleNamespace;
     }
 
-    if (mAnglePath.empty()) {
-        ALOGV("mAnglePath is empty, not creating ANGLE namespace");
+    if (mAnglePath.empty() && !mUseSystemAngle) {
+        ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace");
         return nullptr;
     }
 
-    mAngleNamespace = android_create_namespace("ANGLE",
-                                               nullptr,            // ld_library_path
-                                               mAnglePath.c_str(), // default_library_path
-                                               ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
-                                               nullptr, // permitted_when_isolated_path
-                                               nullptr);
+    // Construct the search paths for system ANGLE.
+    const char* const defaultLibraryPaths =
+#if defined(__LP64__)
+            "/vendor/lib64/egl:/system/lib64/egl";
+#else
+            "/vendor/lib/egl:/system/lib/egl";
+#endif
+
+    // If the application process will run on top of system ANGLE, construct the namespace
+    // with sphal namespace being the parent namespace so that search paths and libraries
+    // are properly inherited.
+    mAngleNamespace =
+            android_create_namespace("ANGLE",
+                                     mUseSystemAngle ? defaultLibraryPaths
+                                                     : mAnglePath.c_str(), // ld_library_path
+                                     mUseSystemAngle ? defaultLibraryPaths
+                                                     : mAnglePath.c_str(), // default_library_path
+                                     ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
+                                     nullptr, // permitted_when_isolated_path
+                                     mUseSystemAngle ? android_get_exported_namespace("sphal")
+                                                     : nullptr); // parent
 
     ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");
 
+    if (!mUseSystemAngle) {
+        return mAngleNamespace;
+    }
+
+    auto vndkNamespace = android_get_exported_namespace("vndk");
+    if (!vndkNamespace) {
+        return nullptr;
+    }
+
+    if (!linkDriverNamespaceLocked(mAngleNamespace, vndkNamespace, "")) {
+        mAngleNamespace = nullptr;
+    }
+
     return mAngleNamespace;
 }
 
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index a1b5e50..e78d038 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -29,6 +29,11 @@
 
 struct NativeLoaderNamespace;
 
+// The GraphicsEnv is a singleton per application process and is used to properly set up the
+// graphics drivers for the application process during application starts. The architecture of
+// the graphics driver loader does not support runtime switch and only supports switch to different
+// graphics drivers when application process launches and hence the only way to switch to different
+// graphics drivers is to completely kill the application process and relaunch the application.
 class GraphicsEnv {
 public:
     static GraphicsEnv& getInstance();
@@ -103,8 +108,8 @@
     // (libraries must be stored uncompressed and page aligned); such elements
     // in the search path must have a '!' after the zip filename, e.g.
     //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
-    void setAngleInfo(const std::string& path, const std::string& packageName,
-                      const std::string& devOptIn, const std::vector<std::string> eglFeatures);
+    void setAngleInfo(const std::string& path, const bool useSystemAngle,
+                      const std::string& packageName, const std::vector<std::string> eglFeatures);
     // Get the ANGLE driver namespace.
     android_namespace_t* getAngleNamespace();
     // Get the app package name.
@@ -132,12 +137,10 @@
     const std::string& getDebugLayersGLES();
 
 private:
-    enum UseAngle { UNKNOWN, YES, NO };
-
-    // Update whether ANGLE should be used.
-    void updateShouldUseAngle();
     // Link updatable driver namespace with llndk and vndk-sp libs.
-    bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
+    bool linkDriverNamespaceLocked(android_namespace_t* destNamespace,
+                                   android_namespace_t* vndkNamespace,
+                                   const std::string& sharedSphalLibraries);
     // Check whether this process is ready to send stats.
     bool readyToSendGpuStatsLocked();
     // Send the initial complete GpuStats to GpuService.
@@ -165,12 +168,12 @@
     std::string mAnglePath;
     // App's package name.
     std::string mPackageName;
-    // ANGLE developer opt in status.
-    std::string mAngleDeveloperOptIn;
     // ANGLE EGL features;
     std::vector<std::string> mAngleEglFeatures;
-    // Use ANGLE flag.
-    UseAngle mShouldUseAngle = UNKNOWN;
+    // Whether ANGLE should be used.
+    bool mShouldUseAngle = false;
+    // Whether loader should load system ANGLE.
+    bool mUseSystemAngle = false;
     // ANGLE namespace.
     android_namespace_t* mAngleNamespace = nullptr;
 
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
index 470f5ed..f777f2f 100644
--- a/libs/input/Android.bp
+++ b/libs/input/Android.bp
@@ -156,6 +156,7 @@
         "libcutils",
         "liblog",
         "libPlatformProperties",
+        "libtinyxml2",
         "libvintf",
     ],
 
@@ -212,6 +213,7 @@
 
             required: [
                 "motion_predictor_model_prebuilt",
+                "motion_predictor_model_config",
             ],
         },
         host: {
diff --git a/libs/input/MotionPredictor.cpp b/libs/input/MotionPredictor.cpp
index a425b93..70a3081 100644
--- a/libs/input/MotionPredictor.cpp
+++ b/libs/input/MotionPredictor.cpp
@@ -36,9 +36,6 @@
 namespace android {
 namespace {
 
-const int64_t PREDICTION_INTERVAL_NANOS =
-        12500000 / 3; // TODO(b/266747937): Get this from the model.
-
 /**
  * Log debug messages about predictions.
  * Enable this via "adb shell setprop log.tag.MotionPredictor DEBUG"
@@ -189,7 +186,7 @@
         // TODO(b/266747654): Stop predictions if predicted pressure is < some threshold.
         coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, predictedPressure[i]);
 
-        predictionTime += PREDICTION_INTERVAL_NANOS;
+        predictionTime += mModel->predictionInterval();
         if (i == 0) {
             hasPredictions = true;
             prediction->initialize(InputEvent::nextId(), event.getDeviceId(), event.getSource(),
@@ -208,7 +205,6 @@
         axisFrom = axisTo;
         axisTo = point;
     }
-    // TODO(b/266747511): Interpolate to futureTime?
     if (!hasPredictions) {
         return nullptr;
     }
diff --git a/libs/input/TfLiteMotionPredictor.cpp b/libs/input/TfLiteMotionPredictor.cpp
index 85fa176..9f4aaa8 100644
--- a/libs/input/TfLiteMotionPredictor.cpp
+++ b/libs/input/TfLiteMotionPredictor.cpp
@@ -36,6 +36,7 @@
 #define ATRACE_TAG ATRACE_TAG_INPUT
 #include <cutils/trace.h>
 #include <log/log.h>
+#include <utils/Timers.h>
 
 #include "tensorflow/lite/core/api/error_reporter.h"
 #include "tensorflow/lite/core/api/op_resolver.h"
@@ -44,6 +45,8 @@
 #include "tensorflow/lite/model.h"
 #include "tensorflow/lite/mutable_op_resolver.h"
 
+#include "tinyxml2.h"
+
 namespace android {
 namespace {
 
@@ -72,16 +75,31 @@
 
 std::string getModelPath() {
 #if defined(__ANDROID__)
-    static const char* oemModel = "/vendor/etc/motion_predictor_model.fb";
+    static const char* oemModel = "/vendor/etc/motion_predictor_model.tflite";
     if (fileExists(oemModel)) {
         return oemModel;
     }
-    return "/system/etc/motion_predictor_model.fb";
+    return "/system/etc/motion_predictor_model.tflite";
 #else
-    return base::GetExecutableDirectory() + "/motion_predictor_model.fb";
+    return base::GetExecutableDirectory() + "/motion_predictor_model.tflite";
 #endif
 }
 
+std::string getConfigPath() {
+    // The config file should be alongside the model file.
+    return base::Dirname(getModelPath()) + "/motion_predictor_config.xml";
+}
+
+int64_t parseXMLInt64(const tinyxml2::XMLElement& configRoot, const char* elementName) {
+    const tinyxml2::XMLElement* element = configRoot.FirstChildElement(elementName);
+    LOG_ALWAYS_FATAL_IF(!element, "Could not find '%s' element", elementName);
+
+    int64_t value = 0;
+    LOG_ALWAYS_FATAL_IF(element->QueryInt64Text(&value) != tinyxml2::XML_SUCCESS,
+                        "Failed to parse %s: %s", elementName, element->GetText());
+    return value;
+}
+
 // A TFLite ErrorReporter that logs to logcat.
 class LoggingErrorReporter : public tflite::ErrorReporter {
 public:
@@ -246,13 +264,23 @@
         PLOG(FATAL) << "Failed to mmap model";
     }
 
+    const std::string configPath = getConfigPath();
+    tinyxml2::XMLDocument configDocument;
+    LOG_ALWAYS_FATAL_IF(configDocument.LoadFile(configPath.c_str()) != tinyxml2::XML_SUCCESS,
+                        "Failed to load config file from %s", configPath.c_str());
+
+    // Parse configuration file.
+    const tinyxml2::XMLElement* configRoot = configDocument.FirstChildElement("motion-predictor");
+    LOG_ALWAYS_FATAL_IF(!configRoot);
+    const nsecs_t predictionInterval = parseXMLInt64(*configRoot, "prediction-interval");
+
     return std::unique_ptr<TfLiteMotionPredictorModel>(
-            new TfLiteMotionPredictorModel(std::move(modelBuffer)));
+            new TfLiteMotionPredictorModel(std::move(modelBuffer), predictionInterval));
 }
 
 TfLiteMotionPredictorModel::TfLiteMotionPredictorModel(
-        std::unique_ptr<android::base::MappedFile> model)
-      : mFlatBuffer(std::move(model)) {
+        std::unique_ptr<android::base::MappedFile> model, nsecs_t predictionInterval)
+      : mFlatBuffer(std::move(model)), mPredictionInterval(predictionInterval) {
     CHECK(mFlatBuffer);
     mErrorReporter = std::make_unique<LoggingErrorReporter>();
     mModel = tflite::FlatBufferModel::VerifyAndBuildFromBuffer(mFlatBuffer->data(),
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index 6aae25d..cadac88 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -64,12 +64,13 @@
         "libcutils",
         "liblog",
         "libPlatformProperties",
+        "libtinyxml2",
         "libutils",
         "libvintf",
     ],
     data: [
         "data/*",
-        ":motion_predictor_model.fb",
+        ":motion_predictor_model",
     ],
     test_options: {
         unit_test: true,
diff --git a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
index 061ec5f..0c7335c 100644
--- a/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
+++ b/libs/renderengine/skia/filters/KawaseBlurFilter.cpp
@@ -17,14 +17,20 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include "KawaseBlurFilter.h"
+#include <SkAlphaType.h>
+#include <SkBlendMode.h>
 #include <SkCanvas.h>
+#include <SkImageInfo.h>
 #include <SkPaint.h>
 #include <SkRRect.h>
 #include <SkRuntimeEffect.h>
+#include <SkShader.h>
 #include <SkSize.h>
 #include <SkString.h>
 #include <SkSurface.h>
 #include <SkTileMode.h>
+#include <include/gpu/GpuTypes.h>
+#include <include/gpu/ganesh/SkSurfaceGanesh.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 
@@ -33,19 +39,18 @@
 namespace skia {
 
 KawaseBlurFilter::KawaseBlurFilter(): BlurFilter() {
-    SkString blurString(R"(
-        uniform shader child;
-        uniform float in_blurOffset;
+    SkString blurString(
+        "uniform shader child;"
+        "uniform float in_blurOffset;"
 
-        half4 main(float2 xy) {
-            half4 c = child.eval(xy);
-            c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset));
-            c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset));
-            c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset));
-            c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset));
-            return half4(c.rgb * 0.2, 1.0);
-        }
-    )");
+        "half4 main(float2 xy) {"
+            "half4 c = child.eval(xy);"
+            "c += child.eval(xy + float2(+in_blurOffset, +in_blurOffset));"
+            "c += child.eval(xy + float2(+in_blurOffset, -in_blurOffset));"
+            "c += child.eval(xy + float2(-in_blurOffset, -in_blurOffset));"
+            "c += child.eval(xy + float2(-in_blurOffset, +in_blurOffset));"
+            "return half4(c.rgb * 0.2, 1.0);"
+        "}");
 
     auto [blurEffect, error] = SkRuntimeEffect::MakeForShader(blurString);
     if (!blurEffect) {
@@ -54,10 +59,43 @@
     mBlurEffect = std::move(blurEffect);
 }
 
-sk_sp<SkImage> KawaseBlurFilter::generate(GrRecordingContext* context, const uint32_t blurRadius,
-                                          const sk_sp<SkImage> input, const SkRect& blurRect)
-    const {
+// Draws the given runtime shader on a GPU (Ganesh) surface and returns the result as an
+// SkImage.
+static sk_sp<SkImage> makeImage(GrRecordingContext* context, SkRuntimeShaderBuilder* builder,
+                                const SkImageInfo& resultInfo) {
+    if (resultInfo.alphaType() == kUnpremul_SkAlphaType ||
+        resultInfo.alphaType() == kUnknown_SkAlphaType) {
+        return nullptr;
+    }
+    constexpr int kSampleCount = 1;
+    constexpr bool kMipmapped = false;
 
+    sk_sp<SkSurface> surface = SkSurfaces::RenderTarget(context,
+                                                        skgpu::Budgeted::kYes,
+                                                        resultInfo,
+                                                        kSampleCount,
+                                                        kTopLeft_GrSurfaceOrigin,
+                                                        nullptr,
+                                                        kMipmapped);
+    if (!surface) {
+        return nullptr;
+    }
+    sk_sp<SkShader> shader = builder->makeShader(nullptr);
+    if (!shader) {
+        return nullptr;
+    }
+    SkPaint paint;
+    paint.setShader(std::move(shader));
+    paint.setBlendMode(SkBlendMode::kSrc);
+    surface->getCanvas()->drawPaint(paint);
+    return surface->makeImageSnapshot();
+}
+
+sk_sp<SkImage> KawaseBlurFilter::generate(GrRecordingContext* context,
+                                          const uint32_t blurRadius,
+                                          const sk_sp<SkImage> input,
+                                          const SkRect& blurRect) const {
+    LOG_ALWAYS_FATAL_IF(context == nullptr, "%s: Needs GPU context", __func__);
     LOG_ALWAYS_FATAL_IF(input == nullptr, "%s: Invalid input image", __func__);
     // Kawase is an approximation of Gaussian, but it behaves differently from it.
     // A radius transformation is required for approximating them, and also to introduce
@@ -83,7 +121,7 @@
             input->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear, blurMatrix);
     blurBuilder.uniform("in_blurOffset") = radiusByPasses * kInputScale;
 
-    sk_sp<SkImage> tmpBlur(blurBuilder.makeImage(context, nullptr, scaledInfo, false));
+    sk_sp<SkImage> tmpBlur = makeImage(context, &blurBuilder, scaledInfo);
 
     // And now we'll build our chain of scaled blur stages
     for (auto i = 1; i < numberOfPasses; i++) {
@@ -91,7 +129,7 @@
         blurBuilder.child("child") =
                 tmpBlur->makeShader(SkTileMode::kClamp, SkTileMode::kClamp, linear);
         blurBuilder.uniform("in_blurOffset") = (float) i * radiusByPasses * kInputScale;
-        tmpBlur = blurBuilder.makeImage(context, nullptr, scaledInfo, false);
+        tmpBlur = makeImage(context, &blurBuilder, scaledInfo);
     }
 
     return tmpBlur;
diff --git a/libs/ultrahdr/icc.cpp b/libs/ultrahdr/icc.cpp
index 1ab3c7c..e41b645 100644
--- a/libs/ultrahdr/icc.cpp
+++ b/libs/ultrahdr/icc.cpp
@@ -19,7 +19,6 @@
 #endif
 
 #include <ultrahdr/icc.h>
-#include <ultrahdr/gainmapmath.h>
 #include <vector>
 #include <utils/Log.h>
 
@@ -218,8 +217,8 @@
     total_length = (((total_length + 2) >> 2) << 2);  // 4 aligned
     sp<DataStruct> dataStruct = sp<DataStruct>::make(total_length);
     dataStruct->write32(Endian_SwapBE32(kTAG_CurveType));     // Type
-    dataStruct->write32(0);                                     // Reserved
-    dataStruct->write32(Endian_SwapBE32(table_entries));  // Value count
+    dataStruct->write32(0);                                   // Reserved
+    dataStruct->write32(Endian_SwapBE32(table_entries));      // Value count
     for (size_t i = 0; i < table_entries; ++i) {
         uint16_t value = reinterpret_cast<const uint16_t*>(table_16)[i];
         dataStruct->write16(value);
@@ -227,14 +226,30 @@
     return dataStruct;
 }
 
-sp<DataStruct> IccHelper::write_trc_tag_for_linear() {
-    int total_length = 16;
-    sp<DataStruct> dataStruct = sp<DataStruct>::make(total_length);
-    dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType));  // Type
-    dataStruct->write32(0);                                      // Reserved
-    dataStruct->write32(Endian_SwapBE16(kExponential_ParaCurveType));
-    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(1.0)));
+sp<DataStruct> IccHelper::write_trc_tag(const TransferFunction& fn) {
+    if (fn.a == 1.f && fn.b == 0.f && fn.c == 0.f
+            && fn.d == 0.f && fn.e == 0.f && fn.f == 0.f) {
+        int total_length = 16;
+        sp<DataStruct> dataStruct = new DataStruct(total_length);
+        dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType));  // Type
+        dataStruct->write32(0);                                    // Reserved
+        dataStruct->write32(Endian_SwapBE16(kExponential_ParaCurveType));
+        dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.g)));
+        return dataStruct;
+    }
 
+    int total_length = 40;
+    sp<DataStruct> dataStruct = new DataStruct(total_length);
+    dataStruct->write32(Endian_SwapBE32(kTAG_ParaCurveType));  // Type
+    dataStruct->write32(0);                                    // Reserved
+    dataStruct->write32(Endian_SwapBE16(kGABCDEF_ParaCurveType));
+    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.g)));
+    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.a)));
+    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.b)));
+    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.c)));
+    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.d)));
+    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.e)));
+    dataStruct->write32(Endian_SwapBE32(float_round_to_fixed(fn.f)));
     return dataStruct;
 }
 
@@ -349,7 +364,7 @@
 
     // The "B" curve is required.
     for (size_t i = 0; i < kNumChannels; ++i) {
-        b_curves_data[i] = write_trc_tag_for_linear();
+        b_curves_data[i] = write_trc_tag(kLinear_TransFun);
     }
 
     // The "A" curve and CLUT are optional.
@@ -362,7 +377,7 @@
 
         a_curves_offset = clut_offset + clut->getLength();
         for (size_t i = 0; i < kNumChannels; ++i) {
-            a_curves_data[i] = write_trc_tag_for_linear();
+            a_curves_data[i] = write_trc_tag(kLinear_TransFun);
         }
     }
 
@@ -460,9 +475,9 @@
             tags.emplace_back(kTAG_bTRC,
                     write_trc_tag(kTrcTableSize, reinterpret_cast<uint8_t*>(trc_table.data())));
         } else {
-            tags.emplace_back(kTAG_rTRC, write_trc_tag_for_linear());
-            tags.emplace_back(kTAG_gTRC, write_trc_tag_for_linear());
-            tags.emplace_back(kTAG_bTRC, write_trc_tag_for_linear());
+            tags.emplace_back(kTAG_rTRC, write_trc_tag(kSRGB_TransFun));
+            tags.emplace_back(kTAG_gTRC, write_trc_tag(kSRGB_TransFun));
+            tags.emplace_back(kTAG_bTRC, write_trc_tag(kSRGB_TransFun));
         }
     }
 
diff --git a/libs/ultrahdr/include/ultrahdr/gainmapmath.h b/libs/ultrahdr/include/ultrahdr/gainmapmath.h
index edf152d..50b4d2f 100644
--- a/libs/ultrahdr/include/ultrahdr/gainmapmath.h
+++ b/libs/ultrahdr/include/ultrahdr/gainmapmath.h
@@ -51,6 +51,23 @@
 typedef Color (*ColorTransformFn)(Color);
 typedef float (*ColorCalculationFn)(Color);
 
+// A transfer function mapping encoded values to linear values,
+// represented by this 7-parameter piecewise function:
+//
+//   linear = sign(encoded) *  (c*|encoded| + f)       , 0 <= |encoded| < d
+//          = sign(encoded) * ((a*|encoded| + b)^g + e), d <= |encoded|
+//
+// (A simple gamma transfer function sets g to gamma and a to 1.)
+typedef struct TransferFunction {
+    float g, a,b,c,d,e,f;
+} TransferFunction;
+
+static constexpr TransferFunction kSRGB_TransFun =
+    { 2.4f, (float)(1/1.055), (float)(0.055/1.055), (float)(1/12.92), 0.04045f, 0.0f, 0.0f };
+
+static constexpr TransferFunction kLinear_TransFun =
+    { 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
+
 inline Color operator+=(Color& lhs, const Color& rhs) {
   lhs.r += rhs.r;
   lhs.g += rhs.g;
@@ -312,7 +329,7 @@
 float hlgOetfLUT(float e);
 Color hlgOetfLUT(Color e);
 
-constexpr size_t kHlgOETFPrecision = 10;
+constexpr size_t kHlgOETFPrecision = 16;
 constexpr size_t kHlgOETFNumEntries = 1 << kHlgOETFPrecision;
 
 /*
@@ -325,7 +342,7 @@
 float hlgInvOetfLUT(float e_gamma);
 Color hlgInvOetfLUT(Color e_gamma);
 
-constexpr size_t kHlgInvOETFPrecision = 10;
+constexpr size_t kHlgInvOETFPrecision = 12;
 constexpr size_t kHlgInvOETFNumEntries = 1 << kHlgInvOETFPrecision;
 
 /*
@@ -338,7 +355,7 @@
 float pqOetfLUT(float e);
 Color pqOetfLUT(Color e);
 
-constexpr size_t kPqOETFPrecision = 10;
+constexpr size_t kPqOETFPrecision = 16;
 constexpr size_t kPqOETFNumEntries = 1 << kPqOETFPrecision;
 
 /*
@@ -351,7 +368,7 @@
 float pqInvOetfLUT(float e_gamma);
 Color pqInvOetfLUT(Color e_gamma);
 
-constexpr size_t kPqInvOETFPrecision = 10;
+constexpr size_t kPqInvOETFPrecision = 12;
 constexpr size_t kPqInvOETFNumEntries = 1 << kPqInvOETFPrecision;
 
 
diff --git a/libs/ultrahdr/include/ultrahdr/icc.h b/libs/ultrahdr/include/ultrahdr/icc.h
index 7f047f8..971b267 100644
--- a/libs/ultrahdr/include/ultrahdr/icc.h
+++ b/libs/ultrahdr/include/ultrahdr/icc.h
@@ -17,6 +17,7 @@
 #ifndef ANDROID_ULTRAHDR_ICC_H
 #define ANDROID_ULTRAHDR_ICC_H
 
+#include <ultrahdr/gainmapmath.h>
 #include <ultrahdr/jpegr.h>
 #include <ultrahdr/jpegrutils.h>
 #include <utils/RefBase.h>
@@ -222,7 +223,7 @@
                                        const ultrahdr_color_gamut gamut);
     static sp<DataStruct> write_xyz_tag(float x, float y, float z);
     static sp<DataStruct> write_trc_tag(const int table_entries, const void* table_16);
-    static sp<DataStruct> write_trc_tag_for_linear();
+    static sp<DataStruct> write_trc_tag(const TransferFunction& fn);
     static float compute_tone_map_gain(const ultrahdr_transfer_function tf, float L);
     static sp<DataStruct> write_cicp_tag(uint32_t color_primaries,
                                          uint32_t transfer_characteristics);
diff --git a/libs/ultrahdr/include/ultrahdr/jpegr.h b/libs/ultrahdr/include/ultrahdr/jpegr.h
index a35fd30..f80496a 100644
--- a/libs/ultrahdr/include/ultrahdr/jpegr.h
+++ b/libs/ultrahdr/include/ultrahdr/jpegr.h
@@ -348,16 +348,6 @@
     status_t extractPrimaryImageAndGainMap(jr_compressed_ptr compressed_jpegr_image,
                                            jr_compressed_ptr primary_image,
                                            jr_compressed_ptr gain_map);
-    /*
-     * This method is called in the decoding pipeline. It will read XMP metadata to find the start
-     * position of the compressed gain map, and will extract the compressed gain map.
-     *
-     * @param compressed_jpegr_image compressed JPEGR image
-     * @param dest destination of compressed gain map
-     * @return NO_ERROR if calculation succeeds, error code if error occurs.
-     */
-    status_t extractGainMap(jr_compressed_ptr compressed_jpegr_image,
-                            jr_compressed_ptr dest);
 
     /*
      * This method is called in the encoding pipeline. It will take the standard 8-bit JPEG image,
diff --git a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h b/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h
index 0641232..5420e1c 100644
--- a/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h
+++ b/libs/ultrahdr/include/ultrahdr/jpegrerrorcode.h
@@ -44,6 +44,7 @@
     ERROR_JPEGR_INVALID_TRANS_FUNC      = JPEGR_IO_ERROR_BASE - 6,
     ERROR_JPEGR_INVALID_METADATA        = JPEGR_IO_ERROR_BASE - 7,
     ERROR_JPEGR_UNSUPPORTED_METADATA    = JPEGR_IO_ERROR_BASE - 8,
+    ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND = JPEGR_IO_ERROR_BASE - 9,
 
     JPEGR_RUNTIME_ERROR_BASE            = -20000,
     ERROR_JPEGR_ENCODE_ERROR            = JPEGR_RUNTIME_ERROR_BASE - 1,
diff --git a/libs/ultrahdr/jpegr.cpp b/libs/ultrahdr/jpegr.cpp
index 9c57f34..5a601bd 100644
--- a/libs/ultrahdr/jpegr.cpp
+++ b/libs/ultrahdr/jpegr.cpp
@@ -539,9 +539,12 @@
     return ERROR_JPEGR_INVALID_NULL_PTR;
   }
 
-  jpegr_compressed_struct primary_image, gain_map;
-  JPEGR_CHECK(extractPrimaryImageAndGainMap(compressed_jpegr_image,
-                                            &primary_image, &gain_map));
+  jpegr_compressed_struct primary_image, gainmap_image;
+  status_t status =
+      extractPrimaryImageAndGainMap(compressed_jpegr_image, &primary_image, &gainmap_image);
+  if (status != NO_ERROR && status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) {
+    return status;
+  }
 
   JpegDecoderHelper jpeg_decoder;
   if (!jpeg_decoder.getCompressedImageParameters(primary_image.data, primary_image.length,
@@ -550,7 +553,7 @@
     return ERROR_JPEGR_DECODE_ERROR;
   }
 
-  return NO_ERROR;
+  return status;
 }
 
 /* Decode API */
@@ -586,90 +589,34 @@
     return ERROR_JPEGR_INVALID_INPUT_TYPE;
   }
 
-  if (output_format == ULTRAHDR_OUTPUT_SDR) {
-    JpegDecoderHelper jpeg_decoder;
-    if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length,
-                                      true)) {
-        return ERROR_JPEGR_DECODE_ERROR;
+  jpegr_compressed_struct primary_image, gainmap_image;
+  status_t status =
+      extractPrimaryImageAndGainMap(compressed_jpegr_image, &primary_image, &gainmap_image);
+  if (status != NO_ERROR) {
+    if (output_format != ULTRAHDR_OUTPUT_SDR || status != ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND) {
+      ALOGE("received invalid compressed jpegr image");
+      return status;
     }
-    jpegr_uncompressed_struct uncompressed_rgba_image;
-    uncompressed_rgba_image.data = jpeg_decoder.getDecompressedImagePtr();
-    uncompressed_rgba_image.width = jpeg_decoder.getDecompressedImageWidth();
-    uncompressed_rgba_image.height = jpeg_decoder.getDecompressedImageHeight();
-    memcpy(dest->data, uncompressed_rgba_image.data,
-           uncompressed_rgba_image.width * uncompressed_rgba_image.height * 4);
-    dest->width = uncompressed_rgba_image.width;
-    dest->height = uncompressed_rgba_image.height;
-
-    if (gain_map == nullptr && exif == nullptr) {
-      return NO_ERROR;
-    }
-
-    if (exif != nullptr) {
-      if (exif->data == nullptr) {
-        return ERROR_JPEGR_INVALID_NULL_PTR;
-      }
-      if (exif->length < jpeg_decoder.getEXIFSize()) {
-        return ERROR_JPEGR_BUFFER_TOO_SMALL;
-      }
-      memcpy(exif->data, jpeg_decoder.getEXIFPtr(), jpeg_decoder.getEXIFSize());
-      exif->length = jpeg_decoder.getEXIFSize();
-    }
-    if (gain_map == nullptr) {
-      return NO_ERROR;
-    }
-  }
-
-  jpegr_compressed_struct compressed_map;
-  JPEGR_CHECK(extractGainMap(compressed_jpegr_image, &compressed_map));
-
-  JpegDecoderHelper gain_map_decoder;
-  if (!gain_map_decoder.decompressImage(compressed_map.data, compressed_map.length)) {
-    return ERROR_JPEGR_DECODE_ERROR;
-  }
-  if ((gain_map_decoder.getDecompressedImageWidth() *
-       gain_map_decoder.getDecompressedImageHeight()) >
-      gain_map_decoder.getDecompressedImageSize()) {
-    return ERROR_JPEGR_CALCULATION_ERROR;
-  }
-
-  if (gain_map != nullptr) {
-    gain_map->width = gain_map_decoder.getDecompressedImageWidth();
-    gain_map->height = gain_map_decoder.getDecompressedImageHeight();
-    int size = gain_map->width * gain_map->height;
-    gain_map->data = malloc(size);
-    memcpy(gain_map->data, gain_map_decoder.getDecompressedImagePtr(), size);
-  }
-
-  ultrahdr_metadata_struct uhdr_metadata;
-  if (!getMetadataFromXMP(static_cast<uint8_t*>(gain_map_decoder.getXMPPtr()),
-                          gain_map_decoder.getXMPSize(), &uhdr_metadata)) {
-    return ERROR_JPEGR_INVALID_METADATA;
-  }
-
-  if (metadata != nullptr) {
-      metadata->version = uhdr_metadata.version;
-      metadata->minContentBoost = uhdr_metadata.minContentBoost;
-      metadata->maxContentBoost = uhdr_metadata.maxContentBoost;
-      metadata->gamma = uhdr_metadata.gamma;
-      metadata->offsetSdr = uhdr_metadata.offsetSdr;
-      metadata->offsetHdr = uhdr_metadata.offsetHdr;
-      metadata->hdrCapacityMin = uhdr_metadata.hdrCapacityMin;
-      metadata->hdrCapacityMax = uhdr_metadata.hdrCapacityMax;
-  }
-
-  if (output_format == ULTRAHDR_OUTPUT_SDR) {
-    return NO_ERROR;
   }
 
   JpegDecoderHelper jpeg_decoder;
-  if (!jpeg_decoder.decompressImage(compressed_jpegr_image->data, compressed_jpegr_image->length)) {
+  if (!jpeg_decoder.decompressImage(primary_image.data, primary_image.length,
+                                    (output_format == ULTRAHDR_OUTPUT_SDR))) {
     return ERROR_JPEGR_DECODE_ERROR;
   }
-  if ((jpeg_decoder.getDecompressedImageWidth() *
-       jpeg_decoder.getDecompressedImageHeight() * 3 / 2) >
-      jpeg_decoder.getDecompressedImageSize()) {
-    return ERROR_JPEGR_CALCULATION_ERROR;
+
+  if (output_format == ULTRAHDR_OUTPUT_SDR) {
+    if ((jpeg_decoder.getDecompressedImageWidth() *
+         jpeg_decoder.getDecompressedImageHeight() * 4) >
+        jpeg_decoder.getDecompressedImageSize()) {
+      return ERROR_JPEGR_CALCULATION_ERROR;
+    }
+  } else {
+    if ((jpeg_decoder.getDecompressedImageWidth() *
+         jpeg_decoder.getDecompressedImageHeight() * 3 / 2) >
+        jpeg_decoder.getDecompressedImageSize()) {
+      return ERROR_JPEGR_CALCULATION_ERROR;
+    }
   }
 
   if (exif != nullptr) {
@@ -683,11 +630,53 @@
     exif->length = jpeg_decoder.getEXIFSize();
   }
 
+  if (output_format == ULTRAHDR_OUTPUT_SDR) {
+    dest->width = jpeg_decoder.getDecompressedImageWidth();
+    dest->height = jpeg_decoder.getDecompressedImageHeight();
+    memcpy(dest->data, jpeg_decoder.getDecompressedImagePtr(), dest->width * dest->height * 4);
+    return NO_ERROR;
+  }
+
+  JpegDecoderHelper gain_map_decoder;
+  if (!gain_map_decoder.decompressImage(gainmap_image.data, gainmap_image.length)) {
+    return ERROR_JPEGR_DECODE_ERROR;
+  }
+  if ((gain_map_decoder.getDecompressedImageWidth() *
+       gain_map_decoder.getDecompressedImageHeight()) >
+      gain_map_decoder.getDecompressedImageSize()) {
+    return ERROR_JPEGR_CALCULATION_ERROR;
+  }
+
   jpegr_uncompressed_struct map;
   map.data = gain_map_decoder.getDecompressedImagePtr();
   map.width = gain_map_decoder.getDecompressedImageWidth();
   map.height = gain_map_decoder.getDecompressedImageHeight();
 
+  if (gain_map != nullptr) {
+    gain_map->width = map.width;
+    gain_map->height = map.height;
+    int size = gain_map->width * gain_map->height;
+    gain_map->data = malloc(size);
+    memcpy(gain_map->data, map.data, size);
+  }
+
+  ultrahdr_metadata_struct uhdr_metadata;
+  if (!getMetadataFromXMP(static_cast<uint8_t*>(gain_map_decoder.getXMPPtr()),
+                          gain_map_decoder.getXMPSize(), &uhdr_metadata)) {
+    return ERROR_JPEGR_INVALID_METADATA;
+  }
+
+  if (metadata != nullptr) {
+    metadata->version = uhdr_metadata.version;
+    metadata->minContentBoost = uhdr_metadata.minContentBoost;
+    metadata->maxContentBoost = uhdr_metadata.maxContentBoost;
+    metadata->gamma = uhdr_metadata.gamma;
+    metadata->offsetSdr = uhdr_metadata.offsetSdr;
+    metadata->offsetHdr = uhdr_metadata.offsetHdr;
+    metadata->hdrCapacityMin = uhdr_metadata.hdrCapacityMin;
+    metadata->hdrCapacityMax = uhdr_metadata.hdrCapacityMax;
+  }
+
   jpegr_uncompressed_struct uncompressed_yuv_420_image;
   uncompressed_yuv_420_image.data = jpeg_decoder.getDecompressedImagePtr();
   uncompressed_yuv_420_image.width = jpeg_decoder.getDecompressedImageWidth();
@@ -1070,7 +1059,7 @@
             }
             case ULTRAHDR_OUTPUT_HDR_PQ:
             {
-#if USE_HLG_OETF_LUT
+#if USE_PQ_OETF_LUT
               ColorTransformFn hdrOetf = pqOetfLUT;
 #else
               ColorTransformFn hdrOetf = pqOetf;
@@ -1131,12 +1120,8 @@
 
   const auto& jpeg_info = jpeg_info_builder.GetInfo();
   const auto& image_ranges = jpeg_info.GetImageRanges();
-  if (image_ranges.empty()) {
-    return ERROR_JPEGR_INVALID_INPUT_TYPE;
-  }
 
-  if (image_ranges.size() != 2) {
-    // Must be 2 JPEG Images
+  if (image_ranges.empty()) {
     return ERROR_JPEGR_INVALID_INPUT_TYPE;
   }
 
@@ -1146,23 +1131,23 @@
     primary_image->length = image_ranges[0].GetLength();
   }
 
+  if (image_ranges.size() == 1) {
+    return ERROR_JPEGR_GAIN_MAP_IMAGE_NOT_FOUND;
+  }
+
   if (gain_map != nullptr) {
     gain_map->data = static_cast<uint8_t*>(compressed_jpegr_image->data) +
                                               image_ranges[1].GetBegin();
     gain_map->length = image_ranges[1].GetLength();
   }
 
-  return NO_ERROR;
-}
-
-
-status_t JpegR::extractGainMap(jr_compressed_ptr compressed_jpegr_image,
-                               jr_compressed_ptr dest) {
-  if (compressed_jpegr_image == nullptr || dest == nullptr) {
-    return ERROR_JPEGR_INVALID_NULL_PTR;
+  // TODO: choose primary image and gain map image carefully
+  if (image_ranges.size() > 2) {
+    ALOGW("Number of jpeg images present %d, primary, gain map images may not be correctly chosen",
+          (int)image_ranges.size());
   }
 
-  return extractPrimaryImageAndGainMap(compressed_jpegr_image, nullptr, dest);
+  return NO_ERROR;
 }
 
 // JPEG/R structure:
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index b007fd3..8f62629 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -185,13 +185,6 @@
     header_libs: [
         "libinputflinger_headers",
     ],
-    target: {
-        host: {
-            static_libs: [
-                "libui-types",
-            ],
-        },
-    },
 }
 
 cc_library_shared {
diff --git a/services/inputflinger/InputDeviceMetricsCollector.cpp b/services/inputflinger/InputDeviceMetricsCollector.cpp
index 999e175..89e37db 100644
--- a/services/inputflinger/InputDeviceMetricsCollector.cpp
+++ b/services/inputflinger/InputDeviceMetricsCollector.cpp
@@ -31,7 +31,7 @@
 
 namespace {
 
-constexpr nanoseconds DEFAULT_USAGE_SESSION_TIMEOUT = std::chrono::minutes(2);
+constexpr nanoseconds DEFAULT_USAGE_SESSION_TIMEOUT = std::chrono::seconds(5);
 
 /**
  * Log debug messages about metrics events logged to statsd.
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 37b3187..1a9f47d 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -34,7 +34,7 @@
 namespace android {
 
 static const bool ENABLE_INPUT_DEVICE_USAGE_METRICS =
-        sysprop::InputProperties::enable_input_device_usage_metrics().value_or(true);
+        sysprop::InputProperties::enable_input_device_usage_metrics().value_or(false);
 
 using gui::FocusRequest;
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index fffb640..29c4e46 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -654,7 +654,6 @@
             TouchedWindow touchedWindow;
             touchedWindow.windowHandle = oldWindow;
             touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_HOVER_EXIT;
-            touchedWindow.pointerIds.set(pointerId);
             out.push_back(touchedWindow);
         }
     }
@@ -673,7 +672,7 @@
             }
             touchedWindow.targetFlags = InputTarget::Flags::DISPATCH_AS_IS;
         }
-        touchedWindow.pointerIds.set(pointerId);
+        touchedWindow.addHoveringPointer(entry.deviceId, pointerId);
         if (canReceiveForegroundTouches(*newWindow->getInfo())) {
             touchedWindow.targetFlags |= InputTarget::Flags::FOREGROUND;
         }
@@ -2195,8 +2194,8 @@
 /**
  * In general, touch should be always split between windows. Some exceptions:
  * 1. Don't split touch is if we have an active pointer down, and a new pointer is going down that's
- * from the same device, *and* the window that's receiving the current pointer does not support
- * split touch.
+ *    from the same device, *and* the window that's receiving the current pointer does not support
+ *    split touch.
  * 2. Don't split mouse events
  */
 bool InputDispatcher::shouldSplitTouch(const TouchState& touchState,
@@ -2219,9 +2218,7 @@
             continue;
         }
 
-        // Eventually, touchedWindow will contain the deviceId of each pointer that's currently
-        // being sent there. For now, use deviceId from touch state.
-        if (entry.deviceId == touchState.deviceId && touchedWindow.pointerIds.any()) {
+        if (touchedWindow.hasTouchingPointers(entry.deviceId)) {
             return false;
         }
     }
@@ -2254,8 +2251,14 @@
     }
 
     bool isSplit = shouldSplitTouch(tempTouchState, entry);
-    const bool switchedDevice = (oldState != nullptr) &&
-            (oldState->deviceId != entry.deviceId || oldState->source != entry.source);
+    bool switchedDevice = false;
+    if (oldState != nullptr) {
+        std::set<int32_t> oldActiveDevices = oldState->getActiveDeviceIds();
+        const bool anotherDeviceIsActive =
+                oldActiveDevices.count(entry.deviceId) == 0 && !oldActiveDevices.empty();
+        switchedDevice |= anotherDeviceIsActive;
+        switchedDevice |= oldState->source != entry.source;
+    }
 
     const bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE ||
                                 maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
@@ -2274,7 +2277,7 @@
     // from another device. However, if the new event is a down event, let's cancel the current
     // touch and let the new one take over.
     if (switchedDevice && wasDown && !isDown) {
-        LOG(INFO) << "Dropping event because a pointer for device " << oldState->deviceId
+        LOG(INFO) << "Dropping event because a pointer for another device "
                   << " is already down in display " << displayId << ": " << entry.getDescription();
         // TODO(b/211379801): test multiple simultaneous input streams.
         outInjectionResult = InputEventInjectionResult::FAILED;
@@ -2284,7 +2287,6 @@
     if (newGesture) {
         // If a new gesture is starting, clear the touch state completely.
         tempTouchState.reset();
-        tempTouchState.deviceId = entry.deviceId;
         tempTouchState.source = entry.source;
         isSplit = false;
     } else if (switchedDevice && maskedAction == AMOTION_EVENT_ACTION_MOVE) {
@@ -2404,7 +2406,7 @@
             // still add a window to the touch state. We should avoid doing that, but some of the
             // later checks ("at least one foreground window") rely on this in order to dispatch
             // the event properly, so that needs to be updated, possibly by looking at InputTargets.
-            tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, pointerIds,
+            tempTouchState.addOrUpdateWindow(windowHandle, targetFlags, entry.deviceId, pointerIds,
                                              isDownOrPointerDown
                                                      ? std::make_optional(entry.eventTime)
                                                      : std::nullopt);
@@ -2428,8 +2430,8 @@
                         if (isSplit) {
                             wallpaperFlags |= InputTarget::Flags::SPLIT;
                         }
-                        tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, pointerIds,
-                                                         entry.eventTime);
+                        tempTouchState.addOrUpdateWindow(wallpaper, wallpaperFlags, entry.deviceId,
+                                                         pointerIds, entry.eventTime);
                     }
                 }
             }
@@ -2440,12 +2442,12 @@
         // which is a specific behaviour that we want.
         const int32_t pointerId = entry.pointerProperties[pointerIndex].id;
         for (TouchedWindow& touchedWindow : tempTouchState.windows) {
-            if (touchedWindow.pointerIds.test(pointerId) &&
-                touchedWindow.pilferedPointerIds.count() > 0) {
+            if (touchedWindow.hasTouchingPointer(entry.deviceId, pointerId) &&
+                touchedWindow.hasPilferingPointers(entry.deviceId)) {
                 // This window is already pilfering some pointers, and this new pointer is also
                 // going to it. Therefore, take over this pointer and don't give it to anyone
                 // else.
-                touchedWindow.pilferedPointerIds.set(pointerId);
+                touchedWindow.addPilferingPointer(entry.deviceId, pointerId);
             }
         }
 
@@ -2517,7 +2519,7 @@
                         tempTouchState.getTouchedWindow(oldTouchedWindowHandle);
                 addWindowTargetLocked(oldTouchedWindowHandle,
                                       InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT, pointerIds,
-                                      touchedWindow.firstDownTimeInTarget, targets);
+                                      touchedWindow.getDownTimeInTarget(entry.deviceId), targets);
 
                 // Make a slippery entrance into the new window.
                 if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2538,13 +2540,14 @@
                     targetFlags |= InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
                 }
 
-                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds,
-                                                 entry.eventTime);
+                tempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags,
+                                                 entry.deviceId, pointerIds, entry.eventTime);
 
                 // Check if the wallpaper window should deliver the corresponding event.
                 slipWallpaperTouch(targetFlags, oldTouchedWindowHandle, newTouchedWindowHandle,
-                                   tempTouchState, pointerId, targets);
-                tempTouchState.removeTouchedPointerFromWindow(pointerId, oldTouchedWindowHandle);
+                                   tempTouchState, entry.deviceId, pointerId, targets);
+                tempTouchState.removeTouchingPointerFromWindow(entry.deviceId, pointerId,
+                                                               oldTouchedWindowHandle);
             }
         }
 
@@ -2558,7 +2561,8 @@
                 if (mDragState && mDragState->dragWindow == touchedWindow.windowHandle) {
                     continue;
                 }
-                touchedWindow.pointerIds.set(entry.pointerProperties[pointerIndex].id);
+                touchedWindow.addTouchingPointer(entry.deviceId,
+                                                 entry.pointerProperties[pointerIndex].id);
             }
         }
     }
@@ -2570,7 +2574,7 @@
         for (const TouchedWindow& touchedWindow : hoveringWindows) {
             std::optional<InputTarget> target =
                     createInputTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
-                                            touchedWindow.firstDownTimeInTarget);
+                                            touchedWindow.getDownTimeInTarget(entry.deviceId));
             if (!target) {
                 continue;
             }
@@ -2627,15 +2631,16 @@
 
     // Output targets from the touch state.
     for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
-        if (touchedWindow.pointerIds.none() && !touchedWindow.hasHoveringPointers(entry.deviceId)) {
+        if (!touchedWindow.hasTouchingPointers(entry.deviceId) &&
+            !touchedWindow.hasHoveringPointers(entry.deviceId)) {
             // Windows with hovering pointers are getting persisted inside TouchState.
             // Do not send this event to those windows.
             continue;
         }
 
         addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
-                              touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget,
-                              targets);
+                              touchedWindow.getTouchingPointers(entry.deviceId),
+                              touchedWindow.getDownTimeInTarget(entry.deviceId), targets);
     }
 
     // During targeted injection, only allow owned targets to receive events
@@ -2689,12 +2694,11 @@
         }
         if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER ||
             maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) {
-            tempTouchState.deviceId = entry.deviceId;
             tempTouchState.source = entry.source;
         }
     } else if (maskedAction == AMOTION_EVENT_ACTION_UP) {
         // Pointer went up.
-        tempTouchState.removeTouchedPointer(entry.pointerProperties[0].id);
+        tempTouchState.removeTouchingPointer(entry.deviceId, entry.pointerProperties[0].id);
     } else if (maskedAction == AMOTION_EVENT_ACTION_CANCEL) {
         // All pointers up or canceled.
         tempTouchState.reset();
@@ -2711,8 +2715,8 @@
 
         for (size_t i = 0; i < tempTouchState.windows.size();) {
             TouchedWindow& touchedWindow = tempTouchState.windows[i];
-            touchedWindow.pointerIds.reset(pointerId);
-            if (touchedWindow.pointerIds.none()) {
+            touchedWindow.removeTouchingPointer(entry.deviceId, pointerId);
+            if (!touchedWindow.hasTouchingPointers(entry.deviceId)) {
                 tempTouchState.windows.erase(tempTouchState.windows.begin() + i);
                 continue;
             }
@@ -4389,7 +4393,7 @@
             const auto touchStateIt = mTouchStatesByDisplay.find(args.displayId);
             if (touchStateIt != mTouchStatesByDisplay.end()) {
                 const TouchState& touchState = touchStateIt->second;
-                if (touchState.deviceId == args.deviceId && touchState.isDown()) {
+                if (touchState.hasTouchingPointers(args.deviceId)) {
                     policyFlags |= POLICY_FLAG_PASS_TO_USER;
                 }
             }
@@ -5427,14 +5431,22 @@
 
         // Find the target touch state and touched window by fromToken.
         auto [state, touchedWindow, displayId] = findTouchStateWindowAndDisplayLocked(fromToken);
+
         if (state == nullptr || touchedWindow == nullptr) {
-            ALOGD("Focus transfer failed because from window is not being touched.");
+            ALOGD("Touch transfer failed because from window is not being touched.");
             return false;
         }
+        std::set<int32_t> deviceIds = touchedWindow->getTouchingDeviceIds();
+        if (deviceIds.size() != 1) {
+            LOG(DEBUG) << "Can't transfer touch. Currently touching devices: " << dumpSet(deviceIds)
+                       << " for window: " << touchedWindow->dump();
+            return false;
+        }
+        const int32_t deviceId = *deviceIds.begin();
 
         sp<WindowInfoHandle> toWindowHandle = getWindowHandleLocked(toToken, displayId);
         if (toWindowHandle == nullptr) {
-            ALOGW("Cannot transfer focus because to window not found.");
+            ALOGW("Cannot transfer touch because to window not found.");
             return false;
         }
 
@@ -5446,7 +5458,7 @@
 
         // Erase old window.
         ftl::Flags<InputTarget::Flags> oldTargetFlags = touchedWindow->targetFlags;
-        std::bitset<MAX_POINTER_ID + 1> pointerIds = touchedWindow->pointerIds;
+        std::bitset<MAX_POINTER_ID + 1> pointerIds = touchedWindow->getTouchingPointers(deviceId);
         sp<WindowInfoHandle> fromWindowHandle = touchedWindow->windowHandle;
         state->removeWindowByToken(fromToken);
 
@@ -5457,7 +5469,8 @@
         if (canReceiveForegroundTouches(*toWindowHandle->getInfo())) {
             newTargetFlags |= InputTarget::Flags::FOREGROUND;
         }
-        state->addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds, downTimeInTarget);
+        state->addOrUpdateWindow(toWindowHandle, newTargetFlags, deviceId, pointerIds,
+                                 downTimeInTarget);
 
         // Store the dragging window.
         if (isDragDrop) {
@@ -5476,16 +5489,15 @@
         std::shared_ptr<Connection> toConnection = getConnectionLocked(toToken);
         if (fromConnection != nullptr && toConnection != nullptr) {
             fromConnection->inputState.mergePointerStateTo(toConnection->inputState);
-            CancelationOptions
-                    options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
-                            "transferring touch focus from this window to another window");
+            CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
+                                       "transferring touch from this window to another window");
             synthesizeCancelationEventsForConnectionLocked(fromConnection, options);
             synthesizePointerDownEventsForConnectionLocked(downTimeInTarget, toConnection,
                                                            newTargetFlags);
 
             // Check if the wallpaper window should deliver the corresponding event.
             transferWallpaperTouch(oldTargetFlags, newTargetFlags, fromWindowHandle, toWindowHandle,
-                                   *state, pointerIds);
+                                   *state, deviceId, pointerIds);
         }
     } // release lock
 
@@ -5969,20 +5981,28 @@
     }
 
     auto [statePtr, windowPtr, displayId] = findTouchStateWindowAndDisplayLocked(token);
-    if (statePtr == nullptr || windowPtr == nullptr || windowPtr->pointerIds.none()) {
+    if (statePtr == nullptr || windowPtr == nullptr) {
         ALOGW("Attempted to pilfer points from a channel without any on-going pointer streams."
               " Ignoring.");
         return BAD_VALUE;
     }
+    std::set<int32_t> deviceIds = windowPtr->getTouchingDeviceIds();
+    if (deviceIds.size() != 1) {
+        LOG(WARNING) << "Can't pilfer. Currently touching devices: " << dumpSet(deviceIds)
+                     << " in window: " << windowPtr->dump();
+        return BAD_VALUE;
+    }
+    const int32_t deviceId = *deviceIds.begin();
 
     TouchState& state = *statePtr;
     TouchedWindow& window = *windowPtr;
     // Send cancel events to all the input channels we're stealing from.
     CancelationOptions options(CancelationOptions::Mode::CANCEL_POINTER_EVENTS,
                                "input channel stole pointer stream");
-    options.deviceId = state.deviceId;
+    options.deviceId = deviceId;
     options.displayId = displayId;
-    options.pointerIds = window.pointerIds;
+    std::bitset<MAX_POINTER_ID + 1> pointerIds = window.getTouchingPointers(deviceId);
+    options.pointerIds = pointerIds;
     std::string canceledWindows;
     for (const TouchedWindow& w : state.windows) {
         const std::shared_ptr<InputChannel> channel =
@@ -5999,9 +6019,9 @@
 
     // Prevent the gesture from being sent to any other windows.
     // This only blocks relevant pointers to be sent to other windows
-    window.pilferedPointerIds |= window.pointerIds;
+    window.addPilferingPointers(deviceId, pointerIds);
 
-    state.cancelPointersForWindowsExcept(window.pointerIds, token);
+    state.cancelPointersForWindowsExcept(deviceId, pointerIds, token);
     return OK;
 }
 
@@ -6781,7 +6801,7 @@
 void InputDispatcher::slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
                                          const sp<WindowInfoHandle>& oldWindowHandle,
                                          const sp<WindowInfoHandle>& newWindowHandle,
-                                         TouchState& state, int32_t pointerId,
+                                         TouchState& state, int32_t deviceId, int32_t pointerId,
                                          std::vector<InputTarget>& targets) const {
     std::bitset<MAX_POINTER_ID + 1> pointerIds;
     pointerIds.set(pointerId);
@@ -6803,8 +6823,8 @@
         addWindowTargetLocked(oldWallpaper,
                               oldTouchedWindow.targetFlags |
                                       InputTarget::Flags::DISPATCH_AS_SLIPPERY_EXIT,
-                              pointerIds, oldTouchedWindow.firstDownTimeInTarget, targets);
-        state.removeTouchedPointerFromWindow(pointerId, oldWallpaper);
+                              pointerIds, oldTouchedWindow.getDownTimeInTarget(deviceId), targets);
+        state.removeTouchingPointerFromWindow(deviceId, pointerId, oldWallpaper);
     }
 
     if (newWallpaper != nullptr) {
@@ -6812,7 +6832,7 @@
                                 InputTarget::Flags::DISPATCH_AS_SLIPPERY_ENTER |
                                         InputTarget::Flags::WINDOW_IS_OBSCURED |
                                         InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED,
-                                pointerIds);
+                                deviceId, pointerIds);
     }
 }
 
@@ -6820,7 +6840,7 @@
                                              ftl::Flags<InputTarget::Flags> newTargetFlags,
                                              const sp<WindowInfoHandle> fromWindowHandle,
                                              const sp<WindowInfoHandle> toWindowHandle,
-                                             TouchState& state,
+                                             TouchState& state, int32_t deviceId,
                                              std::bitset<MAX_POINTER_ID + 1> pointerIds) {
     const bool oldHasWallpaper = oldTargetFlags.test(InputTarget::Flags::FOREGROUND) &&
             fromWindowHandle->getInfo()->inputConfig.test(
@@ -6850,7 +6870,8 @@
                 oldTargetFlags & (InputTarget::Flags::SPLIT | InputTarget::Flags::DISPATCH_AS_IS);
         wallpaperFlags |= InputTarget::Flags::WINDOW_IS_OBSCURED |
                 InputTarget::Flags::WINDOW_IS_PARTIALLY_OBSCURED;
-        state.addOrUpdateWindow(newWallpaper, wallpaperFlags, pointerIds, downTimeInTarget);
+        state.addOrUpdateWindow(newWallpaper, wallpaperFlags, deviceId, pointerIds,
+                                downTimeInTarget);
         std::shared_ptr<Connection> wallpaperConnection =
                 getConnectionLocked(newWallpaper->getToken());
         if (wallpaperConnection != nullptr) {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 78d268d..9cd1666 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -711,14 +711,14 @@
     void slipWallpaperTouch(ftl::Flags<InputTarget::Flags> targetFlags,
                             const sp<android::gui::WindowInfoHandle>& oldWindowHandle,
                             const sp<android::gui::WindowInfoHandle>& newWindowHandle,
-                            TouchState& state, int32_t pointerId,
+                            TouchState& state, int32_t deviceId, int32_t pointerId,
                             std::vector<InputTarget>& targets) const REQUIRES(mLock);
     void transferWallpaperTouch(ftl::Flags<InputTarget::Flags> oldTargetFlags,
                                 ftl::Flags<InputTarget::Flags> newTargetFlags,
                                 const sp<android::gui::WindowInfoHandle> fromWindowHandle,
                                 const sp<android::gui::WindowInfoHandle> toWindowHandle,
-                                TouchState& state, std::bitset<MAX_POINTER_ID + 1> pointerIds)
-            REQUIRES(mLock);
+                                TouchState& state, int32_t deviceId,
+                                std::bitset<MAX_POINTER_ID + 1> pointerIds) REQUIRES(mLock);
 
     sp<android::gui::WindowInfoHandle> findWallpaperWindowBelow(
             const sp<android::gui::WindowInfoHandle>& windowHandle) const REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 0a61d48..dcbb366 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -31,18 +31,34 @@
     *this = TouchState();
 }
 
-void TouchState::removeTouchedPointer(int32_t pointerId) {
+std::set<int32_t> TouchState::getActiveDeviceIds() const {
+    std::set<int32_t> out;
+    for (const TouchedWindow& w : windows) {
+        std::set<int32_t> deviceIds = w.getActiveDeviceIds();
+        out.insert(deviceIds.begin(), deviceIds.end());
+    }
+    return out;
+}
+
+bool TouchState::hasTouchingPointers(int32_t deviceId) const {
+    return std::any_of(windows.begin(), windows.end(), [&](const TouchedWindow& window) {
+        return window.hasTouchingPointers(deviceId);
+    });
+}
+
+void TouchState::removeTouchingPointer(int32_t removedDeviceId, int32_t pointerId) {
     for (TouchedWindow& touchedWindow : windows) {
-        touchedWindow.removeTouchingPointer(pointerId);
+        touchedWindow.removeTouchingPointer(removedDeviceId, pointerId);
     }
     clearWindowsWithoutPointers();
 }
 
-void TouchState::removeTouchedPointerFromWindow(
-        int32_t pointerId, const sp<android::gui::WindowInfoHandle>& windowHandle) {
+void TouchState::removeTouchingPointerFromWindow(
+        int32_t removedDeviceId, int32_t pointerId,
+        const sp<android::gui::WindowInfoHandle>& windowHandle) {
     for (TouchedWindow& touchedWindow : windows) {
         if (touchedWindow.windowHandle == windowHandle) {
-            touchedWindow.removeTouchingPointer(pointerId);
+            touchedWindow.removeTouchingPointer(removedDeviceId, pointerId);
             clearWindowsWithoutPointers();
             return;
         }
@@ -58,13 +74,14 @@
 
 void TouchState::clearWindowsWithoutPointers() {
     std::erase_if(windows, [](const TouchedWindow& w) {
-        return w.pointerIds.none() && !w.hasHoveringPointers();
+        return !w.hasTouchingPointers() && !w.hasHoveringPointers();
     });
 }
 
 void TouchState::addOrUpdateWindow(const sp<WindowInfoHandle>& windowHandle,
                                    ftl::Flags<InputTarget::Flags> targetFlags,
-                                   std::bitset<MAX_POINTER_ID + 1> pointerIds,
+                                   int32_t addedDeviceId,
+                                   std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
                                    std::optional<nsecs_t> firstDownTimeInTarget) {
     for (TouchedWindow& touchedWindow : windows) {
         // We do not compare windows by token here because two windows that share the same token
@@ -75,11 +92,11 @@
                 touchedWindow.targetFlags.clear(InputTarget::Flags::DISPATCH_AS_IS);
             }
             // For cases like hover enter/exit or DISPATCH_AS_OUTSIDE a touch window might not have
-            // downTime set initially. Need to update existing window when an pointer is down for
-            // the window.
-            touchedWindow.pointerIds |= pointerIds;
-            if (!touchedWindow.firstDownTimeInTarget.has_value()) {
-                touchedWindow.firstDownTimeInTarget = firstDownTimeInTarget;
+            // downTime set initially. Need to update existing window when a pointer is down for the
+            // window.
+            touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds);
+            if (firstDownTimeInTarget) {
+                touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget);
             }
             return;
         }
@@ -87,8 +104,10 @@
     TouchedWindow touchedWindow;
     touchedWindow.windowHandle = windowHandle;
     touchedWindow.targetFlags = targetFlags;
-    touchedWindow.pointerIds = pointerIds;
-    touchedWindow.firstDownTimeInTarget = firstDownTimeInTarget;
+    touchedWindow.addTouchingPointers(addedDeviceId, touchingPointerIds);
+    if (firstDownTimeInTarget) {
+        touchedWindow.trySetDownTimeInTarget(addedDeviceId, *firstDownTimeInTarget);
+    }
     windows.push_back(touchedWindow);
 }
 
@@ -130,12 +149,12 @@
     }
 }
 
-void TouchState::cancelPointersForWindowsExcept(std::bitset<MAX_POINTER_ID + 1> pointerIds,
+void TouchState::cancelPointersForWindowsExcept(int32_t touchedDeviceId,
+                                                std::bitset<MAX_POINTER_ID + 1> pointerIds,
                                                 const sp<IBinder>& token) {
-    if (pointerIds.none()) return;
-    std::for_each(windows.begin(), windows.end(), [&pointerIds, &token](TouchedWindow& w) {
+    std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
         if (w.windowHandle->getToken() != token) {
-            w.pointerIds &= ~pointerIds;
+            w.removeTouchingPointers(touchedDeviceId, pointerIds);
         }
     });
     clearWindowsWithoutPointers();
@@ -149,24 +168,29 @@
  */
 void TouchState::cancelPointersForNonPilferingWindows() {
     // First, find all pointers that are being pilfered, across all windows
-    std::bitset<MAX_POINTER_ID + 1> allPilferedPointerIds;
-    std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](const TouchedWindow& w) {
-        allPilferedPointerIds |= w.pilferedPointerIds;
-    });
+    std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> allPilferedPointerIdsByDevice;
+    for (const TouchedWindow& w : windows) {
+        for (const auto& [iterDeviceId, pilferedPointerIds] : w.getPilferingPointers()) {
+            allPilferedPointerIdsByDevice[iterDeviceId] |= pilferedPointerIds;
+        }
+    };
 
     // Optimization: most of the time, pilfering does not occur
-    if (allPilferedPointerIds.none()) return;
+    if (allPilferedPointerIdsByDevice.empty()) return;
 
     // Now, remove all pointers from every window that's being pilfered by other windows.
     // For example, if window A is pilfering pointer 1 (only), and window B is pilfering pointer 2
     // (only), the remove pointer 2 from window A and pointer 1 from window B. Usually, the set of
     // pilfered pointers will be disjoint across all windows, but there's no reason to cause that
     // limitation here.
-    std::for_each(windows.begin(), windows.end(), [&allPilferedPointerIds](TouchedWindow& w) {
-        std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
-                w.pilferedPointerIds ^ allPilferedPointerIds;
-        w.pointerIds &= ~pilferedByOtherWindows;
-    });
+    for (const auto& [iterDeviceId, allPilferedPointerIds] : allPilferedPointerIdsByDevice) {
+        std::for_each(windows.begin(), windows.end(), [&](TouchedWindow& w) {
+            std::bitset<MAX_POINTER_ID + 1> pilferedByOtherWindows =
+                    w.getPilferingPointers(iterDeviceId) ^ allPilferedPointerIds;
+            // Remove all pointers pilfered by other windows
+            w.removeTouchingPointers(iterDeviceId, pilferedByOtherWindows);
+        });
+    }
     clearWindowsWithoutPointers();
 }
 
@@ -216,7 +240,7 @@
 
 bool TouchState::isDown() const {
     return std::any_of(windows.begin(), windows.end(),
-                       [](const TouchedWindow& window) { return window.pointerIds.any(); });
+                       [](const TouchedWindow& window) { return window.hasTouchingPointers(); });
 }
 
 bool TouchState::hasHoveringPointers() const {
@@ -245,19 +269,15 @@
 void TouchState::removeAllPointersForDevice(int32_t removedDeviceId) {
     for (TouchedWindow& window : windows) {
         window.removeAllHoveringPointersForDevice(removedDeviceId);
+        window.removeAllTouchingPointersForDevice(removedDeviceId);
     }
-    if (deviceId == removedDeviceId) {
-        for (TouchedWindow& window : windows) {
-            window.removeAllTouchingPointers();
-        }
-    }
+
     clearWindowsWithoutPointers();
 }
 
 std::string TouchState::dump() const {
     std::string out;
-    out += StringPrintf("deviceId=%d, source=%s\n", deviceId,
-                        inputEventSourceToString(source).c_str());
+    out += StringPrintf("source=%s\n", inputEventSourceToString(source).c_str());
     if (!windows.empty()) {
         out += "  Windows:\n";
         for (size_t i = 0; i < windows.size(); i++) {
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 15b840f..1bda0fb 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -29,8 +29,6 @@
 namespace inputdispatcher {
 
 struct TouchState {
-    // id of the device that is currently down, others are rejected
-    int32_t deviceId = -1;
     // source of the device that is current down, others are rejected
     uint32_t source = 0;
 
@@ -43,24 +41,28 @@
     void reset();
     void clearWindowsWithoutPointers();
 
-    void removeTouchedPointer(int32_t pointerId);
-    void removeTouchedPointerFromWindow(int32_t pointerId,
-                                        const sp<android::gui::WindowInfoHandle>& windowHandle);
+    std::set<int32_t> getActiveDeviceIds() const;
+
+    bool hasTouchingPointers(int32_t device) const;
+    void removeTouchingPointer(int32_t deviceId, int32_t pointerId);
+    void removeTouchingPointerFromWindow(int32_t deviceId, int32_t pointerId,
+                                         const sp<android::gui::WindowInfoHandle>& windowHandle);
     void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
-                           ftl::Flags<InputTarget::Flags> targetFlags,
-                           std::bitset<MAX_POINTER_ID + 1> pointerIds,
+                           ftl::Flags<InputTarget::Flags> targetFlags, int32_t deviceId,
+                           std::bitset<MAX_POINTER_ID + 1> touchingPointerIds,
                            std::optional<nsecs_t> firstDownTimeInTarget = std::nullopt);
     void addHoveringPointerToWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
                                     int32_t deviceId, int32_t hoveringPointerId);
     void removeHoveringPointer(int32_t deviceId, int32_t hoveringPointerId);
     void clearHoveringPointers();
 
-    void removeAllPointersForDevice(int32_t removedDeviceId);
+    void removeAllPointersForDevice(int32_t deviceId);
     void removeWindowByToken(const sp<IBinder>& token);
     void filterNonAsIsTouchWindows();
 
     // Cancel pointers for current set of windows except the window with particular binder token.
-    void cancelPointersForWindowsExcept(std::bitset<MAX_POINTER_ID + 1> pointerIds,
+    void cancelPointersForWindowsExcept(int32_t deviceId,
+                                        std::bitset<MAX_POINTER_ID + 1> pointerIds,
                                         const sp<IBinder>& token);
     // Cancel pointers for current set of non-pilfering windows i.e. windows with isPilferingWindow
     // set to false.
diff --git a/services/inputflinger/dispatcher/TouchedWindow.cpp b/services/inputflinger/dispatcher/TouchedWindow.cpp
index d55d657..ae16520 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.cpp
+++ b/services/inputflinger/dispatcher/TouchedWindow.cpp
@@ -16,6 +16,7 @@
 
 #include "TouchedWindow.h"
 
+#include <android-base/logging.h>
 #include <android-base/stringprintf.h>
 #include <input/PrintTools.h>
 
@@ -26,67 +27,236 @@
 namespace inputdispatcher {
 
 bool TouchedWindow::hasHoveringPointers() const {
-    return !mHoveringPointerIdsByDevice.empty();
+    for (const auto& [_, state] : mDeviceStates) {
+        if (state.hoveringPointerIds.any()) {
+            return true;
+        }
+    }
+    return false;
 }
 
 bool TouchedWindow::hasHoveringPointers(int32_t deviceId) const {
-    return mHoveringPointerIdsByDevice.find(deviceId) != mHoveringPointerIdsByDevice.end();
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return false;
+    }
+    const DeviceState& state = stateIt->second;
+
+    return state.hoveringPointerIds.any();
 }
 
 void TouchedWindow::clearHoveringPointers() {
-    mHoveringPointerIdsByDevice.clear();
+    for (auto& [_, state] : mDeviceStates) {
+        state.hoveringPointerIds.reset();
+    }
+
+    std::erase_if(mDeviceStates, [](const auto& pair) { return !pair.second.hasPointers(); });
 }
 
 bool TouchedWindow::hasHoveringPointer(int32_t deviceId, int32_t pointerId) const {
-    auto it = mHoveringPointerIdsByDevice.find(deviceId);
-    if (it == mHoveringPointerIdsByDevice.end()) {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
         return false;
     }
-    return it->second.test(pointerId);
+    const DeviceState& state = stateIt->second;
+
+    return state.hoveringPointerIds.test(pointerId);
 }
 
 void TouchedWindow::addHoveringPointer(int32_t deviceId, int32_t pointerId) {
-    const auto [it, _] = mHoveringPointerIdsByDevice.insert({deviceId, {}});
-    it->second.set(pointerId);
+    mDeviceStates[deviceId].hoveringPointerIds.set(pointerId);
 }
 
-void TouchedWindow::removeTouchingPointer(int32_t pointerId) {
-    pointerIds.reset(pointerId);
-    pilferedPointerIds.reset(pointerId);
-    if (pointerIds.none()) {
-        firstDownTimeInTarget.reset();
+void TouchedWindow::addTouchingPointer(int32_t deviceId, int32_t pointerId) {
+    mDeviceStates[deviceId].touchingPointerIds.set(pointerId);
+}
+
+void TouchedWindow::addTouchingPointers(int32_t deviceId,
+                                        std::bitset<MAX_POINTER_ID + 1> pointers) {
+    mDeviceStates[deviceId].touchingPointerIds |= pointers;
+}
+
+bool TouchedWindow::hasTouchingPointers() const {
+    for (const auto& [_, state] : mDeviceStates) {
+        if (state.touchingPointerIds.any()) {
+            return true;
+        }
+    }
+    return false;
+}
+
+bool TouchedWindow::hasTouchingPointers(int32_t deviceId) const {
+    return getTouchingPointers(deviceId).any();
+}
+
+bool TouchedWindow::hasTouchingPointer(int32_t deviceId, int32_t pointerId) const {
+    return getTouchingPointers(deviceId).test(pointerId);
+}
+
+std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getTouchingPointers(int32_t deviceId) const {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return {};
+    }
+    const DeviceState& state = stateIt->second;
+
+    return state.touchingPointerIds;
+}
+
+void TouchedWindow::removeTouchingPointer(int32_t deviceId, int32_t pointerId) {
+    std::bitset<MAX_POINTER_ID + 1> pointerIds;
+    pointerIds.set(pointerId, true);
+
+    removeTouchingPointers(deviceId, pointerIds);
+}
+
+void TouchedWindow::removeTouchingPointers(int32_t deviceId,
+                                           std::bitset<MAX_POINTER_ID + 1> pointers) {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return;
+    }
+    DeviceState& state = stateIt->second;
+
+    state.touchingPointerIds &= ~pointers;
+    state.pilferingPointerIds &= ~pointers;
+
+    if (!state.hasPointers()) {
+        mDeviceStates.erase(stateIt);
     }
 }
 
-void TouchedWindow::removeAllTouchingPointers() {
-    pointerIds.reset();
+std::set<int32_t> TouchedWindow::getTouchingDeviceIds() const {
+    std::set<int32_t> deviceIds;
+    for (const auto& [deviceId, _] : mDeviceStates) {
+        deviceIds.insert(deviceId);
+    }
+    return deviceIds;
+}
+
+std::set<int32_t> TouchedWindow::getActiveDeviceIds() const {
+    std::set<int32_t> out;
+    for (const auto& [deviceId, _] : mDeviceStates) {
+        out.emplace(deviceId);
+    }
+    return out;
+}
+
+bool TouchedWindow::hasPilferingPointers(int32_t deviceId) const {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return false;
+    }
+    const DeviceState& state = stateIt->second;
+
+    return state.pilferingPointerIds.any();
+}
+
+void TouchedWindow::addPilferingPointers(int32_t deviceId,
+                                         std::bitset<MAX_POINTER_ID + 1> pointerIds) {
+    mDeviceStates[deviceId].pilferingPointerIds |= pointerIds;
+}
+
+void TouchedWindow::addPilferingPointer(int32_t deviceId, int32_t pointerId) {
+    mDeviceStates[deviceId].pilferingPointerIds.set(pointerId);
+}
+
+std::bitset<MAX_POINTER_ID + 1> TouchedWindow::getPilferingPointers(int32_t deviceId) const {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return {};
+    }
+    const DeviceState& state = stateIt->second;
+
+    return state.pilferingPointerIds;
+}
+
+std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> TouchedWindow::getPilferingPointers() const {
+    std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> out;
+    for (const auto& [deviceId, state] : mDeviceStates) {
+        out.emplace(deviceId, state.pilferingPointerIds);
+    }
+    return out;
+}
+
+std::optional<nsecs_t> TouchedWindow::getDownTimeInTarget(int32_t deviceId) const {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return {};
+    }
+    const DeviceState& state = stateIt->second;
+    return state.downTimeInTarget;
+}
+
+void TouchedWindow::trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime) {
+    auto [stateIt, _] = mDeviceStates.try_emplace(deviceId);
+    DeviceState& state = stateIt->second;
+
+    if (!state.downTimeInTarget) {
+        state.downTimeInTarget = downTime;
+    }
+}
+
+void TouchedWindow::removeAllTouchingPointersForDevice(int32_t deviceId) {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return;
+    }
+    DeviceState& state = stateIt->second;
+
+    state.touchingPointerIds.reset();
+    state.pilferingPointerIds.reset();
+    state.downTimeInTarget.reset();
+
+    if (!state.hasPointers()) {
+        mDeviceStates.erase(stateIt);
+    }
 }
 
 void TouchedWindow::removeHoveringPointer(int32_t deviceId, int32_t pointerId) {
-    const auto it = mHoveringPointerIdsByDevice.find(deviceId);
-    if (it == mHoveringPointerIdsByDevice.end()) {
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
         return;
     }
-    it->second.set(pointerId, false);
+    DeviceState& state = stateIt->second;
 
-    if (it->second.none()) {
-        mHoveringPointerIdsByDevice.erase(deviceId);
+    state.hoveringPointerIds.set(pointerId, false);
+
+    if (!state.hasPointers()) {
+        mDeviceStates.erase(stateIt);
     }
 }
 
 void TouchedWindow::removeAllHoveringPointersForDevice(int32_t deviceId) {
-    mHoveringPointerIdsByDevice.erase(deviceId);
+    const auto stateIt = mDeviceStates.find(deviceId);
+    if (stateIt == mDeviceStates.end()) {
+        return;
+    }
+    DeviceState& state = stateIt->second;
+
+    state.hoveringPointerIds.reset();
+
+    if (!state.hasPointers()) {
+        mDeviceStates.erase(stateIt);
+    }
+}
+
+std::string TouchedWindow::deviceStateToString(const TouchedWindow::DeviceState& state) {
+    return StringPrintf("[touchingPointerIds=%s, "
+                        "downTimeInTarget=%s, hoveringPointerIds=%s, pilferingPointerIds=%s]",
+                        bitsetToString(state.touchingPointerIds).c_str(),
+                        toString(state.downTimeInTarget).c_str(),
+                        bitsetToString(state.hoveringPointerIds).c_str(),
+                        bitsetToString(state.pilferingPointerIds).c_str());
 }
 
 std::string TouchedWindow::dump() const {
     std::string out;
-    std::string hoveringPointers =
-            dumpMap(mHoveringPointerIdsByDevice, constToString, bitsetToString);
-    out += StringPrintf("name='%s', pointerIds=%s, targetFlags=%s, firstDownTimeInTarget=%s, "
-                        "mHoveringPointerIdsByDevice=%s, pilferedPointerIds=%s\n",
-                        windowHandle->getName().c_str(), bitsetToString(pointerIds).c_str(),
-                        targetFlags.string().c_str(), toString(firstDownTimeInTarget).c_str(),
-                        hoveringPointers.c_str(), bitsetToString(pilferedPointerIds).c_str());
+    std::string deviceStates =
+            dumpMap(mDeviceStates, constToString, TouchedWindow::deviceStateToString);
+    out += StringPrintf("name='%s', targetFlags=%s, mDeviceStates=%s\n",
+                        windowHandle->getName().c_str(), targetFlags.string().c_str(),
+                        deviceStates.c_str());
     return out;
 }
 
diff --git a/services/inputflinger/dispatcher/TouchedWindow.h b/services/inputflinger/dispatcher/TouchedWindow.h
index 43e7169..81393fc 100644
--- a/services/inputflinger/dispatcher/TouchedWindow.h
+++ b/services/inputflinger/dispatcher/TouchedWindow.h
@@ -20,6 +20,7 @@
 #include <input/Input.h>
 #include <utils/BitSet.h>
 #include <bitset>
+#include <set>
 #include "InputTarget.h"
 
 namespace android {
@@ -30,28 +31,66 @@
 struct TouchedWindow {
     sp<gui::WindowInfoHandle> windowHandle;
     ftl::Flags<InputTarget::Flags> targetFlags;
-    std::bitset<MAX_POINTER_ID + 1> pointerIds;
-    // The pointer ids of the pointers that this window is currently pilfering
-    std::bitset<MAX_POINTER_ID + 1> pilferedPointerIds;
-    // Time at which the first action down occurred on this window.
-    // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE scenario.
-    std::optional<nsecs_t> firstDownTimeInTarget;
 
+    // Hovering
     bool hasHoveringPointers() const;
     bool hasHoveringPointers(int32_t deviceId) const;
-
     bool hasHoveringPointer(int32_t deviceId, int32_t pointerId) const;
     void addHoveringPointer(int32_t deviceId, int32_t pointerId);
     void removeHoveringPointer(int32_t deviceId, int32_t pointerId);
-    void removeTouchingPointer(int32_t pointerId);
 
-    void removeAllTouchingPointers();
+    // Touching
+    bool hasTouchingPointer(int32_t deviceId, int32_t pointerId) const;
+    bool hasTouchingPointers() const;
+    bool hasTouchingPointers(int32_t deviceId) const;
+    std::bitset<MAX_POINTER_ID + 1> getTouchingPointers(int32_t deviceId) const;
+    void addTouchingPointer(int32_t deviceId, int32_t pointerId);
+    void addTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers);
+    void removeTouchingPointer(int32_t deviceId, int32_t pointerId);
+    void removeTouchingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointers);
+    /**
+     * Get the currently active touching device id. If there isn't exactly 1 touching device, return
+     * nullopt.
+     */
+    std::set<int32_t> getTouchingDeviceIds() const;
+    /**
+     * The ids of devices that are currently touching or hovering.
+     */
+    std::set<int32_t> getActiveDeviceIds() const;
+
+    // Pilfering pointers
+    bool hasPilferingPointers(int32_t deviceId) const;
+    void addPilferingPointers(int32_t deviceId, std::bitset<MAX_POINTER_ID + 1> pointerIds);
+    void addPilferingPointer(int32_t deviceId, int32_t pointerId);
+    std::bitset<MAX_POINTER_ID + 1> getPilferingPointers(int32_t deviceId) const;
+    std::map<int32_t, std::bitset<MAX_POINTER_ID + 1>> getPilferingPointers() const;
+
+    // Down time
+    std::optional<nsecs_t> getDownTimeInTarget(int32_t deviceId) const;
+    void trySetDownTimeInTarget(int32_t deviceId, nsecs_t downTime);
+
+    void removeAllTouchingPointersForDevice(int32_t deviceId);
     void removeAllHoveringPointersForDevice(int32_t deviceId);
     void clearHoveringPointers();
     std::string dump() const;
 
 private:
-    std::map<int32_t /*deviceId*/, std::bitset<MAX_POINTER_ID + 1>> mHoveringPointerIdsByDevice;
+    struct DeviceState {
+        std::bitset<MAX_POINTER_ID + 1> touchingPointerIds;
+        // The pointer ids of the pointers that this window is currently pilfering, by device
+        std::bitset<MAX_POINTER_ID + 1> pilferingPointerIds;
+        // Time at which the first action down occurred on this window, for each device
+        // NOTE: This is not initialized in case of HOVER entry/exit and DISPATCH_AS_OUTSIDE
+        // scenario.
+        std::optional<nsecs_t> downTimeInTarget;
+        std::bitset<MAX_POINTER_ID + 1> hoveringPointerIds;
+
+        bool hasPointers() const { return touchingPointerIds.any() || hoveringPointerIds.any(); };
+    };
+
+    std::map<int32_t /*deviceId*/, DeviceState> mDeviceStates;
+
+    static std::string deviceStateToString(const TouchedWindow::DeviceState& state);
 };
 
 } // namespace inputdispatcher
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index bf07f72..89c80bc 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -195,7 +195,6 @@
         "ScreenCaptureOutput.cpp",
         "StartPropertySetThread.cpp",
         "SurfaceFlinger.cpp",
-        "SurfaceFlingerConfig.cpp",
         "SurfaceFlingerDefaultFactory.cpp",
         "Tracing/LayerTracing.cpp",
         "Tracing/TransactionTracing.cpp",
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2789fa6..f6ca9e2 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -78,19 +78,18 @@
                     .setDisplayHeight(ANativeWindow_getHeight(args.nativeWindow.get()))
                     .setNativeWindow(std::move(args.nativeWindow))
                     .setDisplaySurface(std::move(args.displaySurface))
-                    .setMaxTextureCacheSize(static_cast<size_t>(
-                            mFlinger->getConfig().maxFrameBufferAcquiredBuffers))
+                    .setMaxTextureCacheSize(
+                            static_cast<size_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers))
                     .build());
 
-    if (!mFlinger->getConfig().disableClientCompositionCache &&
-        mFlinger->getConfig().maxFrameBufferAcquiredBuffers > 0) {
+    if (!mFlinger->mDisableClientCompositionCache &&
+        SurfaceFlinger::maxFrameBufferAcquiredBuffers > 0) {
         mCompositionDisplay->createClientCompositionCache(
-                static_cast<uint32_t>(mFlinger->getConfig().maxFrameBufferAcquiredBuffers));
+                static_cast<uint32_t>(SurfaceFlinger::maxFrameBufferAcquiredBuffers));
     }
 
-    mCompositionDisplay->setPredictCompositionStrategy(
-            mFlinger->getConfig().predictCompositionStrategy);
-    mCompositionDisplay->setTreat170mAsSrgb(mFlinger->getConfig().treat170mAsSrgb);
+    mCompositionDisplay->setPredictCompositionStrategy(mFlinger->mPredictCompositionStrategy);
+    mCompositionDisplay->setTreat170mAsSrgb(mFlinger->mTreat170mAsSrgb);
     mCompositionDisplay->createDisplayColorProfile(
             compositionengine::DisplayColorProfileCreationArgsBuilder()
                     .setHasWideColorGamut(args.hasWideColorGamut)
@@ -412,22 +411,23 @@
                            capabilities.getDesiredMinLuminance());
 }
 
-void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc) {
+void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner,
+                                             bool showRenderRate, bool showInMiddle) {
     if (!enable) {
         mRefreshRateOverlay.reset();
         return;
     }
 
     ftl::Flags<RefreshRateOverlay::Features> features;
-    if (mFlinger->getConfig().refreshRateOverlay.showSpinner) {
+    if (showSpinner) {
         features |= RefreshRateOverlay::Features::Spinner;
     }
 
-    if (mFlinger->getConfig().refreshRateOverlay.showRenderRate) {
+    if (showRenderRate) {
         features |= RefreshRateOverlay::Features::RenderRate;
     }
 
-    if (mFlinger->getConfig().refreshRateOverlay.showInMiddle) {
+    if (showInMiddle) {
         features |= RefreshRateOverlay::Features::ShowInMiddle;
     }
 
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index d2a9fb6..dc5f8a8 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -236,7 +236,8 @@
     }
 
     // Enables an overlay to be displayed with the current refresh rate
-    void enableRefreshRateOverlay(bool enable, bool setByHwc) REQUIRES(kMainThreadContext);
+    void enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner, bool showRenderRate,
+                                  bool showInMiddle) REQUIRES(kMainThreadContext);
     void updateRefreshRateOverlayRate(Fps displayFps, Fps renderFps, bool setByHwc = false);
     bool isRefreshRateOverlayEnabled() const { return mRefreshRateOverlay != nullptr; }
     bool onKernelTimerChanged(std::optional<DisplayModeId>, bool timerExpired);
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 14fff77..ce602a8 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -50,8 +50,7 @@
 
 FramebufferSurface::FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
                                        const sp<IGraphicBufferConsumer>& consumer,
-                                       const ui::Size& size, const ui::Size& maxSize,
-                                       int maxAcquiredBufferCount)
+                                       const ui::Size& size, const ui::Size& maxSize)
       : ConsumerBase(consumer),
         mDisplayId(displayId),
         mMaxSize(maxSize),
@@ -71,7 +70,8 @@
                                        GRALLOC_USAGE_HW_COMPOSER);
     const auto limitedSize = limitSize(size);
     mConsumer->setDefaultBufferSize(limitedSize.width, limitedSize.height);
-    mConsumer->setMaxAcquiredBufferCount(maxAcquiredBufferCount);
+    mConsumer->setMaxAcquiredBufferCount(
+            SurfaceFlinger::maxFrameBufferAcquiredBuffers - 1);
 
     for (size_t i = 0; i < sizeof(mHwcBufferIds) / sizeof(mHwcBufferIds[0]); ++i) {
         mHwcBufferIds[i] = UINT64_MAX;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index 5a1d14f..0b863da 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -42,7 +42,7 @@
 public:
     FramebufferSurface(HWComposer& hwc, PhysicalDisplayId displayId,
                        const sp<IGraphicBufferConsumer>& consumer, const ui::Size& size,
-                       const ui::Size& maxSize, int maxAcquiredBufferCount);
+                       const ui::Size& maxSize);
 
     virtual status_t beginFrame(bool mustRecompose);
     virtual status_t prepareFrame(CompositionType compositionType);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index d759c12..d62075e 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -50,7 +50,7 @@
                                              const sp<IGraphicBufferProducer>& sink,
                                              const sp<IGraphicBufferProducer>& bqProducer,
                                              const sp<IGraphicBufferConsumer>& bqConsumer,
-                                             const std::string& name, bool useHwcForRgbToYuv)
+                                             const std::string& name)
       : ConsumerBase(bqConsumer),
         mHwc(hwc),
         mDisplayId(displayId),
@@ -69,7 +69,7 @@
         mOutputFence(Fence::NO_FENCE),
         mFbProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
         mOutputProducerSlot(BufferQueue::INVALID_BUFFER_SLOT),
-        mForceHwcCopy(useHwcForRgbToYuv) {
+        mForceHwcCopy(SurfaceFlinger::useHwcForRgbToYuv) {
     mSource[SOURCE_SINK] = sink;
     mSource[SOURCE_SCRATCH] = bqProducer;
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 8a56d5f..be06e2b 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -77,8 +77,7 @@
 public:
     VirtualDisplaySurface(HWComposer&, VirtualDisplayId, const sp<IGraphicBufferProducer>& sink,
                           const sp<IGraphicBufferProducer>& bqProducer,
-                          const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name,
-                          bool useHwcForRgbToYuv);
+                          const sp<IGraphicBufferConsumer>& bqConsumer, const std::string& name);
 
     //
     // DisplaySurface interface
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 8e1b8f2..5a010e8 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2562,7 +2562,7 @@
 compositionengine::OutputLayer* Layer::findOutputLayerForDisplay(
         const DisplayDevice* display) const {
     if (!display) return nullptr;
-    if (!mFlinger->getConfig().layerLifecycleManagerEnabled) {
+    if (!mFlinger->mLayerLifecycleManagerEnabled) {
         return display->getCompositionDisplay()->getOutputLayerForLayer(
                 getCompositionEngineLayerFE());
     }
@@ -2907,7 +2907,7 @@
 
 void Layer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
     for (const auto& handle : mDrawingState.callbackHandles) {
-        if (mFlinger->getConfig().layerLifecycleManagerEnabled) {
+        if (mFlinger->mLayerLifecycleManagerEnabled) {
             handle->transformHint = mTransformHint;
         } else {
             handle->transformHint = mSkipReportingTransformHint
@@ -3162,7 +3162,7 @@
     mFlinger->mTimeStats->setPostTime(layerId, mDrawingState.frameNumber, getName().c_str(),
                                       mOwnerUid, postTime, getGameMode());
 
-    if (mFlinger->getConfig().legacyFrontEndEnabled) {
+    if (mFlinger->mLegacyFrontEndEnabled) {
         recordLayerHistoryBufferUpdate(getLayerProps());
     }
 
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index 9c1944b..51d4ff8 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -78,7 +78,7 @@
         mTransform = mLayerTransform.inverse();
     }
 
-    if (mFlinger.getConfig().layerLifecycleManagerEnabled) {
+    if (mFlinger.mLayerLifecycleManagerEnabled) {
         drawLayers();
         return;
     }
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 03f3b40..8f658d5 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -322,7 +322,7 @@
     };
 
     std::function<std::vector<std::pair<Layer*, sp<LayerFE>>>()> getLayerSnapshots;
-    if (mFlinger.getConfig().layerLifecycleManagerEnabled) {
+    if (mFlinger.mLayerLifecycleManagerEnabled) {
         auto filterFn = [&](const frontend::LayerSnapshot& snapshot,
                             bool& outStopTraversal) -> bool {
             const Rect bounds =
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 60c0904..ba13293 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -214,6 +214,16 @@
 // TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
 constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
 
+float getDensityFromProperty(const char* property, bool required) {
+    char value[PROPERTY_VALUE_MAX];
+    const float density = property_get(property, value, nullptr) > 0 ? std::atof(value) : 0.f;
+    if (!density && required) {
+        ALOGE("%s must be defined as a build property", property);
+        return FALLBACK_DENSITY;
+    }
+    return density;
+}
+
 // Currently we only support V0_SRGB and DISPLAY_P3 as composition preference.
 bool validateCompositionDataspace(Dataspace dataspace) {
     return dataspace == Dataspace::V0_SRGB || dataspace == Dataspace::DISPLAY_P3;
@@ -312,6 +322,18 @@
 static const int MAX_TRACING_MEMORY = 1024 * 1024 * 1024; // 1GB
 
 // ---------------------------------------------------------------------------
+int64_t SurfaceFlinger::dispSyncPresentTimeOffset;
+bool SurfaceFlinger::useHwcForRgbToYuv;
+bool SurfaceFlinger::hasSyncFramework;
+int64_t SurfaceFlinger::maxFrameBufferAcquiredBuffers;
+int64_t SurfaceFlinger::minAcquiredBuffers = 1;
+uint32_t SurfaceFlinger::maxGraphicsWidth;
+uint32_t SurfaceFlinger::maxGraphicsHeight;
+bool SurfaceFlinger::useContextPriority;
+Dataspace SurfaceFlinger::defaultCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
+Dataspace SurfaceFlinger::wideColorGamutCompositionDataspace = Dataspace::V0_SRGB;
+ui::PixelFormat SurfaceFlinger::wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
 LatchUnsignaledConfig SurfaceFlinger::enableLatchUnsignaledConfig;
 
 std::string decodeDisplayColorSetting(DisplayColorSetting displayColorSetting) {
@@ -338,35 +360,136 @@
 
 ui::Transform::RotationFlags SurfaceFlinger::sActiveDisplayRotationFlags = ui::Transform::ROT_0;
 
-SurfaceFlinger::SurfaceFlinger(surfaceflinger::Config& config)
-      : mConfig(&config),
-        mDebugFlashDelay(base::GetUintProperty("debug.sf.showupdates"s, 0u)),
+SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
+      : mFactory(factory),
+        mPid(getpid()),
         mTimeStats(std::make_shared<impl::TimeStats>()),
-        mFrameTracer(mConfig->factory->createFrameTracer()),
-        mFrameTimeline(mConfig->factory->createFrameTimeline(mTimeStats, mConfig->pid)),
-        mCompositionEngine(mConfig->factory->createCompositionEngine()),
+        mFrameTracer(mFactory.createFrameTracer()),
+        mFrameTimeline(mFactory.createFrameTimeline(mTimeStats, mPid)),
+        mCompositionEngine(mFactory.createCompositionEngine()),
+        mHwcServiceName(base::GetProperty("debug.sf.hwc_service_name"s, "default"s)),
         mTunnelModeEnabledReporter(sp<TunnelModeEnabledReporter>::make()),
+        mEmulatedDisplayDensity(getDensityFromProperty("qemu.sf.lcd_density", false)),
+        mInternalDisplayDensity(
+                getDensityFromProperty("ro.sf.lcd_density", !mEmulatedDisplayDensity)),
         mPowerAdvisor(std::make_unique<Hwc2::impl::PowerAdvisor>(*this)),
         mWindowInfosListenerInvoker(sp<WindowInfosListenerInvoker>::make()) {
-    ATRACE_CALL();
-    ALOGI("SurfaceFlinger is starting.");
-    ALOGI("Using HWComposer service: %s", mConfig->hwcServiceName.c_str());
-    ALOGI_IF(mConfig->backpressureGpuComposition, "Enabling backpressure for GPU composition");
-    ALOGI_IF(!mConfig->supportsBlur, "Disabling blur effects, they are not supported.");
-    ALOGI_IF(mConfig->trebleTestingOverride, "Enabling Treble testing override");
+    ALOGI("Using HWComposer service: %s", mHwcServiceName.c_str());
+}
 
-    if (mConfig->trebleTestingOverride) {
+SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
+    ATRACE_CALL();
+    ALOGI("SurfaceFlinger is starting");
+
+    hasSyncFramework = running_without_sync_framework(true);
+
+    dispSyncPresentTimeOffset = present_time_offset_from_vsync_ns(0);
+
+    useHwcForRgbToYuv = force_hwc_copy_for_virtual_displays(false);
+
+    maxFrameBufferAcquiredBuffers = max_frame_buffer_acquired_buffers(2);
+    minAcquiredBuffers =
+            SurfaceFlingerProperties::min_acquired_buffers().value_or(minAcquiredBuffers);
+
+    maxGraphicsWidth = std::max(max_graphics_width(0), 0);
+    maxGraphicsHeight = std::max(max_graphics_height(0), 0);
+
+    mSupportsWideColor = has_wide_color_display(false);
+    mDefaultCompositionDataspace =
+            static_cast<ui::Dataspace>(default_composition_dataspace(Dataspace::V0_SRGB));
+    mWideColorGamutCompositionDataspace = static_cast<ui::Dataspace>(wcg_composition_dataspace(
+            mSupportsWideColor ? Dataspace::DISPLAY_P3 : Dataspace::V0_SRGB));
+    defaultCompositionDataspace = mDefaultCompositionDataspace;
+    wideColorGamutCompositionDataspace = mWideColorGamutCompositionDataspace;
+    defaultCompositionPixelFormat = static_cast<ui::PixelFormat>(
+            default_composition_pixel_format(ui::PixelFormat::RGBA_8888));
+    wideColorGamutCompositionPixelFormat =
+            static_cast<ui::PixelFormat>(wcg_composition_pixel_format(ui::PixelFormat::RGBA_8888));
+
+    mColorSpaceAgnosticDataspace =
+            static_cast<ui::Dataspace>(color_space_agnostic_dataspace(Dataspace::UNKNOWN));
+
+    mLayerCachingEnabled = [] {
+        const bool enable =
+                android::sysprop::SurfaceFlingerProperties::enable_layer_caching().value_or(false);
+        return base::GetBoolProperty(std::string("debug.sf.enable_layer_caching"), enable);
+    }();
+
+    useContextPriority = use_context_priority(true);
+
+    mInternalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
+
+    // debugging stuff...
+    char value[PROPERTY_VALUE_MAX];
+
+    property_get("ro.build.type", value, "user");
+    mIsUserBuild = strcmp(value, "user") == 0;
+
+    mDebugFlashDelay = base::GetUintProperty("debug.sf.showupdates"s, 0u);
+
+    mBackpressureGpuComposition = base::GetBoolProperty("debug.sf.enable_gl_backpressure"s, true);
+    ALOGI_IF(mBackpressureGpuComposition, "Enabling backpressure for GPU composition");
+
+    property_get("ro.surface_flinger.supports_background_blur", value, "0");
+    bool supportsBlurs = atoi(value);
+    mSupportsBlur = supportsBlurs;
+    ALOGI_IF(!mSupportsBlur, "Disabling blur effects, they are not supported.");
+
+    const size_t defaultListSize = MAX_LAYERS;
+    auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
+    mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
+    mGraphicBufferProducerListSizeLogThreshold =
+            std::max(static_cast<int>(0.95 *
+                                      static_cast<double>(mMaxGraphicBufferProducerListSize)),
+                     1);
+
+    property_get("debug.sf.luma_sampling", value, "1");
+    mLumaSampling = atoi(value);
+
+    property_get("debug.sf.disable_client_composition_cache", value, "0");
+    mDisableClientCompositionCache = atoi(value);
+
+    property_get("debug.sf.predict_hwc_composition_strategy", value, "1");
+    mPredictCompositionStrategy = atoi(value);
+
+    property_get("debug.sf.treat_170m_as_sRGB", value, "0");
+    mTreat170mAsSrgb = atoi(value);
+
+    mIgnoreHwcPhysicalDisplayOrientation =
+            base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s, false);
+
+    // We should be reading 'persist.sys.sf.color_saturation' here
+    // but since /data may be encrypted, we need to wait until after vold
+    // comes online to attempt to read the property. The property is
+    // instead read after the boot animation
+
+    if (base::GetBoolProperty("debug.sf.treble_testing_override"s, false)) {
         // Without the override SurfaceFlinger cannot connect to HIDL
         // services that are not listed in the manifests.  Considered
         // deriving the setting from the set service name, but it
         // would be brittle if the name that's not 'default' is used
         // for production purposes later on.
+        ALOGI("Enabling Treble testing override");
         android::hardware::details::setTrebleTestingOverride(true);
     }
 
-    if (!mConfig->isUserBuild && mConfig->enableTransactionTracing) {
+    // TODO (b/270966065) Update the HWC based refresh rate overlay to support spinner
+    mRefreshRateOverlaySpinner = property_get_bool("debug.sf.show_refresh_rate_overlay_spinner", 0);
+    mRefreshRateOverlayRenderRate =
+            property_get_bool("debug.sf.show_refresh_rate_overlay_render_rate", 0);
+    mRefreshRateOverlayShowInMiddle =
+            property_get_bool("debug.sf.show_refresh_rate_overlay_in_middle", 0);
+
+    if (!mIsUserBuild && base::GetBoolProperty("debug.sf.enable_transaction_tracing"s, true)) {
         mTransactionTracing.emplace();
     }
+
+    mIgnoreHdrCameraLayers = ignore_hdr_camera_layers(false);
+
+    mLayerLifecycleManagerEnabled =
+            base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s, false);
+    mLegacyFrontEndEnabled = !mLayerLifecycleManagerEnabled ||
+            base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false);
 }
 
 LatchUnsignaledConfig SurfaceFlinger::getLatchUnsignaledConfig() {
@@ -693,18 +816,17 @@
     // Get a RenderEngine for the given display / config (can't fail)
     // TODO(b/77156734): We need to stop casting and use HAL types when possible.
     // Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
-    auto builder =
-            renderengine::RenderEngineCreationArgs::Builder()
-                    .setPixelFormat(static_cast<int32_t>(mConfig->defaultCompositionPixelFormat))
-                    .setImageCacheSize(mConfig->maxFrameBufferAcquiredBuffers)
-                    .setUseColorManagerment(useColorManagement)
-                    .setEnableProtectedContext(enable_protected_contents(false))
-                    .setPrecacheToneMapperShaderOnly(false)
-                    .setSupportsBackgroundBlur(mConfig->supportsBlur)
-                    .setContextPriority(
-                            mConfig->useContextPriority
-                                    ? renderengine::RenderEngine::ContextPriority::REALTIME
-                                    : renderengine::RenderEngine::ContextPriority::MEDIUM);
+    auto builder = renderengine::RenderEngineCreationArgs::Builder()
+                           .setPixelFormat(static_cast<int32_t>(defaultCompositionPixelFormat))
+                           .setImageCacheSize(maxFrameBufferAcquiredBuffers)
+                           .setUseColorManagerment(useColorManagement)
+                           .setEnableProtectedContext(enable_protected_contents(false))
+                           .setPrecacheToneMapperShaderOnly(false)
+                           .setSupportsBackgroundBlur(mSupportsBlur)
+                           .setContextPriority(
+                                   useContextPriority
+                                           ? renderengine::RenderEngine::ContextPriority::REALTIME
+                                           : renderengine::RenderEngine::ContextPriority::MEDIUM);
     if (auto type = chooseRenderEngineTypeViaSysProp()) {
         builder.setRenderEngineType(type.value());
     }
@@ -719,7 +841,7 @@
     }
 
     mCompositionEngine->setTimeStats(mTimeStats);
-    mCompositionEngine->setHwComposer(getFactory().createHWComposer(mConfig->hwcServiceName));
+    mCompositionEngine->setHwComposer(getFactory().createHWComposer(mHwcServiceName));
     mCompositionEngine->getHwComposer().setCallback(*this);
     ClientCache::getInstance().setRenderEngine(&getRenderEngine());
 
@@ -909,11 +1031,11 @@
     info->connectionType = snapshot.connectionType();
     info->deviceProductInfo = snapshot.deviceProductInfo();
 
-    if (mConfig->emulatedDisplayDensity) {
-        info->density = mConfig->emulatedDisplayDensity;
+    if (mEmulatedDisplayDensity) {
+        info->density = mEmulatedDisplayDensity;
     } else {
         info->density = info->connectionType == ui::DisplayConnectionType::Internal
-                ? mConfig->internalDisplayDensity
+                ? mInternalDisplayDensity
                 : FALLBACK_DENSITY;
     }
     info->density /= ACONFIGURATION_DENSITY_MEDIUM;
@@ -976,7 +1098,7 @@
         info->supportedDisplayModes.push_back(outMode);
     }
 
-    info->supportedColorModes = snapshot.filterColorModes(mConfig->supportsWideColor);
+    info->supportedColorModes = snapshot.filterColorModes(mSupportsWideColor);
 
     const PhysicalDisplayId displayId = snapshot.displayId();
 
@@ -1374,7 +1496,7 @@
     }
 
     // TODO(b/229846990): For now, assume that all internal displays have the same primaries.
-    primaries = mConfig->internalDisplayPrimaries;
+    primaries = mInternalDisplayPrimaries;
     return NO_ERROR;
 }
 
@@ -1398,7 +1520,7 @@
         const auto& [display, snapshotRef] = *displayOpt;
         const auto& snapshot = snapshotRef.get();
 
-        const auto modes = snapshot.filterColorModes(mConfig->supportsWideColor);
+        const auto modes = snapshot.filterColorModes(mSupportsWideColor);
         const bool exists = std::find(modes.begin(), modes.end(), mode) != modes.end();
 
         if (mode < ui::ColorMode::NATIVE || !exists) {
@@ -1704,7 +1826,7 @@
     }
 
     *outIsWideColorDisplay =
-            display->isPrimary() ? mConfig->supportsWideColor : display->hasWideColorGamut();
+            display->isPrimary() ? mSupportsWideColor : display->hasWideColorGamut();
     return NO_ERROR;
 }
 
@@ -1725,12 +1847,10 @@
         Dataspace* outDataspace, ui::PixelFormat* outPixelFormat,
         Dataspace* outWideColorGamutDataspace,
         ui::PixelFormat* outWideColorGamutPixelFormat) const {
-    *outDataspace =
-            mOverrideDefaultCompositionDataspace.value_or(mConfig->defaultCompositionDataspace);
-    *outPixelFormat = mConfig->defaultCompositionPixelFormat;
-    *outWideColorGamutDataspace = mOverrideWideColorGamutCompositionDataspace.value_or(
-            mConfig->wideColorGamutCompositionDataspace);
-    *outWideColorGamutPixelFormat = mConfig->wideColorGamutCompositionPixelFormat;
+    *outDataspace = mDefaultCompositionDataspace;
+    *outPixelFormat = defaultCompositionPixelFormat;
+    *outWideColorGamutDataspace = mWideColorGamutCompositionDataspace;
+    *outWideColorGamutPixelFormat = wideColorGamutCompositionPixelFormat;
     return NO_ERROR;
 }
 
@@ -2193,7 +2313,7 @@
                      .displays = mFrontEndDisplayInfos,
                      .displayChanges = mFrontEndDisplayInfosChanged,
                      .globalShadowSettings = mDrawingState.globalShadowSettings,
-                     .supportsBlur = mConfig->supportsBlur,
+                     .supportsBlur = mSupportsBlur,
                      .forceFullDamage = mForceFullDamage,
                      .supportedLayerGenericMetadata =
                              getHwComposer().getSupportedLayerGenericMetadata(),
@@ -2213,7 +2333,7 @@
     mustComposite |= mLayerLifecycleManager.getGlobalChanges().get() != 0;
 
     bool newDataLatched = false;
-    if (!mConfig->legacyFrontEndEnabled) {
+    if (!mLegacyFrontEndEnabled) {
         ATRACE_NAME("DisplayCallbackAndStatsUpdates");
         applyTransactions(update.transactions, vsyncId);
         const nsecs_t latchTime = systemTime();
@@ -2307,7 +2427,7 @@
     }
 
     if (pacesetterFrameTarget.isFramePending()) {
-        if (mConfig->backpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) {
+        if (mBackpressureGpuComposition || pacesetterFrameTarget.didMissHwcFrame()) {
             scheduleCommit(FrameHint::kNone);
             return false;
         }
@@ -2338,7 +2458,7 @@
         mPowerAdvisor->updateTargetWorkDuration(idealVsyncPeriod);
     }
 
-    if (mConfig->refreshRateOverlay.showSpinner) {
+    if (mRefreshRateOverlaySpinner) {
         Mutex::Autolock lock(mStateLock);
         if (const auto display = getDefaultDisplayDeviceLocked()) {
             display->animateRefreshRateOverlay();
@@ -2354,12 +2474,12 @@
 
         const bool flushTransactions = clearTransactionFlags(eTransactionFlushNeeded);
         bool transactionsAreEmpty;
-        if (mConfig->legacyFrontEndEnabled) {
+        if (mLegacyFrontEndEnabled) {
             mustComposite |=
                     updateLayerSnapshotsLegacy(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
                                                flushTransactions, transactionsAreEmpty);
         }
-        if (mConfig->layerLifecycleManagerEnabled) {
+        if (mLayerLifecycleManagerEnabled) {
             mustComposite |=
                     updateLayerSnapshots(vsyncId, pacesetterFrameTarget.frameBeginTime().ns(),
                                          flushTransactions, transactionsAreEmpty);
@@ -2465,7 +2585,7 @@
     refreshArgs.outputColorSetting = useColorManagement
             ? mDisplayColorSetting
             : compositionengine::OutputColorSetting::kUnmanaged;
-    refreshArgs.colorSpaceAgnosticDataspace = mConfig->colorSpaceAgnosticDataspace;
+    refreshArgs.colorSpaceAgnosticDataspace = mColorSpaceAgnosticDataspace;
     refreshArgs.forceOutputColorMode = mForceColorMode;
 
     refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
@@ -2619,7 +2739,7 @@
     // Even though the camera layer may be using an HDR transfer function or otherwise be "HDR"
     // the device may need to avoid boosting the brightness as a result of these layers to
     // reduce power consumption during camera recording
-    if (mConfig->ignoreHdrCameraLayers) {
+    if (mIgnoreHdrCameraLayers) {
         if (snapshot.externalTexture &&
             (snapshot.externalTexture->getUsage() & GRALLOC_USAGE_HW_CAMERA_WRITE) != 0) {
             return false;
@@ -2650,7 +2770,7 @@
     if (!id) {
         return ui::ROTATION_0;
     }
-    if (!mConfig->ignoreHwcPhysicalDisplayOrientation &&
+    if (!mIgnoreHwcPhysicalDisplayOrientation &&
         getHwComposer().getComposer()->isSupported(
                 Hwc2::Composer::OptionalFeature::PhysicalDisplayOrientation)) {
         switch (getHwComposer().getPhysicalDisplayOrientation(*id)) {
@@ -2817,7 +2937,7 @@
                         }
                     };
 
-            if (mConfig->layerLifecycleManagerEnabled) {
+            if (mLayerLifecycleManagerEnabled) {
                 mLayerSnapshotBuilder.forEachVisibleSnapshot(
                         [&, compositionDisplay = compositionDisplay](
                                 std::unique_ptr<frontend::LayerSnapshot>& snapshot) {
@@ -2869,7 +2989,7 @@
     const bool isDisplayConnected =
             defaultDisplay && getHwComposer().isConnected(defaultDisplay->getPhysicalId());
 
-    if (!mConfig->hasSyncFramework) {
+    if (!hasSyncFramework) {
         if (isDisplayConnected && defaultDisplay->isPoweredOn()) {
             mScheduler->enableHardwareVsync(defaultDisplay->getPhysicalId());
         }
@@ -2910,7 +3030,7 @@
             if (!layer->hasTrustedPresentationListener()) {
                 return;
             }
-            const frontend::LayerSnapshot* snapshot = mConfig->layerLifecycleManagerEnabled
+            const frontend::LayerSnapshot* snapshot = mLayerLifecycleManagerEnabled
                     ? mLayerSnapshotBuilder.getSnapshot(layer->sequence)
                     : layer->getLayerSnapshot();
             std::optional<const DisplayDevice*> displayOpt = std::nullopt;
@@ -3305,7 +3425,7 @@
     builder.setPowerAdvisor(mPowerAdvisor.get());
     builder.setName(state.displayName);
     auto compositionDisplay = getCompositionEngine().createDisplay(builder.build());
-    compositionDisplay->setLayerCachingEnabled(mConfig->layerCachingEnabled);
+    compositionDisplay->setLayerCachingEnabled(mLayerCachingEnabled);
 
     sp<compositionengine::DisplaySurface> displaySurface;
     sp<IGraphicBufferProducer> producer;
@@ -3317,8 +3437,7 @@
         const auto displayId = VirtualDisplayId::tryCast(compositionDisplay->getId());
         LOG_FATAL_IF(!displayId);
         auto surface = sp<VirtualDisplaySurface>::make(getHwComposer(), *displayId, state.surface,
-                                                       bqProducer, bqConsumer, state.displayName,
-                                                       mConfig->useHwcForRgbToYuv);
+                                                       bqProducer, bqConsumer, state.displayName);
         displaySurface = surface;
         producer = std::move(surface);
     } else {
@@ -3328,11 +3447,10 @@
                  state.surface.get());
         const auto displayId = PhysicalDisplayId::tryCast(compositionDisplay->getId());
         LOG_FATAL_IF(!displayId);
-        displaySurface = sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer,
-                                                      state.physical->activeMode->getResolution(),
-                                                      ui::Size(mConfig->maxGraphicsWidth,
-                                                               mConfig->maxGraphicsHeight),
-                                                      mConfig->maxFrameBufferAcquiredBuffers);
+        displaySurface =
+                sp<FramebufferSurface>::make(getHwComposer(), *displayId, bqConsumer,
+                                             state.physical->activeMode->getResolution(),
+                                             ui::Size(maxGraphicsWidth, maxGraphicsHeight));
         producer = bqProducer;
     }
 
@@ -3513,7 +3631,7 @@
     // Commit display transactions.
     const bool displayTransactionNeeded = transactionFlags & eDisplayTransactionNeeded;
     mFrontEndDisplayInfosChanged = displayTransactionNeeded;
-    if (displayTransactionNeeded && !mConfig->layerLifecycleManagerEnabled) {
+    if (displayTransactionNeeded && !mLayerLifecycleManagerEnabled) {
         processDisplayChangesLocked();
         mFrontEndDisplayInfos.clear();
         for (const auto& [_, display] : mDisplays) {
@@ -3713,7 +3831,7 @@
     outWindowInfos.reserve(sNumWindowInfos);
     sNumWindowInfos = 0;
 
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         mLayerSnapshotBuilder.forEachInputSnapshot(
                 [&outWindowInfos](const frontend::LayerSnapshot& snapshot) {
                     outWindowInfos.push_back(snapshot.inputInfo);
@@ -3837,7 +3955,7 @@
     if (display->refreshRateSelector().kernelIdleTimerController()) {
         features |= Feature::kKernelIdleTimer;
     }
-    if (mConfig->backpressureGpuComposition) {
+    if (mBackpressureGpuComposition) {
         features |= Feature::kBackpressureGpuComposition;
     }
 
@@ -4383,7 +4501,7 @@
 void SurfaceFlinger::addTransactionReadyFilters() {
     mTransactionHandler.addTransactionReadyFilter(
             std::bind(&SurfaceFlinger::transactionReadyTimelineCheck, this, std::placeholders::_1));
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         mTransactionHandler.addTransactionReadyFilter(
                 std::bind(&SurfaceFlinger::transactionReadyBufferCheck, this,
                           std::placeholders::_1));
@@ -4614,7 +4732,7 @@
                                            const std::vector<ListenerCallbacks>& listenerCallbacks,
                                            int originPid, int originUid, uint64_t transactionId) {
     uint32_t transactionFlags = 0;
-    if (!mConfig->layerLifecycleManagerEnabled) {
+    if (!mLayerLifecycleManagerEnabled) {
         for (DisplayState& display : displays) {
             transactionFlags |= setDisplayStateLocked(display);
         }
@@ -4629,12 +4747,12 @@
 
     uint32_t clientStateFlags = 0;
     for (auto& resolvedState : states) {
-        if (mConfig->legacyFrontEndEnabled) {
+        if (mLegacyFrontEndEnabled) {
             clientStateFlags |=
                     setClientStateLocked(frameTimelineInfo, resolvedState, desiredPresentTime,
                                          isAutoTimestamp, postTime, transactionId);
 
-        } else /* mConfig->layerLifecycleManagerEnabled */ {
+        } else /*mLayerLifecycleManagerEnabled*/ {
             clientStateFlags |= updateLayerCallbacksAndStats(frameTimelineInfo, resolvedState,
                                                              desiredPresentTime, isAutoTimestamp,
                                                              postTime, transactionId);
@@ -4708,7 +4826,7 @@
     }
 
     mFrontEndDisplayInfosChanged = mTransactionFlags & eDisplayTransactionNeeded;
-    if (mFrontEndDisplayInfosChanged && !mConfig->legacyFrontEndEnabled) {
+    if (mFrontEndDisplayInfosChanged && !mLegacyFrontEndEnabled) {
         processDisplayChangesLocked();
         mFrontEndDisplayInfos.clear();
         for (const auto& [_, display] : mDisplays) {
@@ -4911,7 +5029,7 @@
         if (layer->setCornerRadius(s.cornerRadius))
             flags |= eTraversalNeeded;
     }
-    if (what & layer_state_t::eBackgroundBlurRadiusChanged && mConfig->supportsBlur) {
+    if (what & layer_state_t::eBackgroundBlurRadiusChanged && mSupportsBlur) {
         if (layer->setBackgroundBlurRadius(s.backgroundBlurRadius)) flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eBlurRegionsChanged) {
@@ -5315,7 +5433,7 @@
         return result;
     }
 
-    if (mConfig->legacyFrontEndEnabled) {
+    if (mLegacyFrontEndEnabled) {
         std::scoped_lock<std::mutex> lock(mMirrorDisplayLock);
         mMirrorDisplays.emplace_back(layerStack, outResult.handle, args.client);
     }
@@ -5422,10 +5540,9 @@
     const nsecs_t now = systemTime();
     state.desiredPresentTime = now;
     state.postTime = now;
-    state.originPid = mConfig->pid;
+    state.originPid = mPid;
     state.originUid = static_cast<int>(getuid());
-    const uint64_t transactionId =
-            (static_cast<uint64_t>(mConfig->pid) << 32) | mUniqueTransactionId++;
+    const uint64_t transactionId = (static_cast<uint64_t>(mPid) << 32) | mUniqueTransactionId++;
     state.id = transactionId;
 
     // reset screen orientation and use primary layer stack
@@ -5445,7 +5562,7 @@
     std::vector<TransactionState> transactions;
     transactions.emplace_back(state);
 
-    if (mConfig->legacyFrontEndEnabled) {
+    if (mLegacyFrontEndEnabled) {
         applyTransactions(transactions, VsyncId{0});
     } else {
         applyAndCommitDisplayTransactionStates(transactions);
@@ -5741,13 +5858,13 @@
 void SurfaceFlinger::appendSfConfigString(std::string& result) const {
     result.append(" [sf");
 
-    StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, mConfig->dispSyncPresentTimeOffset);
-    StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", mConfig->useHwcForRgbToYuv);
+    StringAppendF(&result, " PRESENT_TIME_OFFSET=%" PRId64, dispSyncPresentTimeOffset);
+    StringAppendF(&result, " FORCE_HWC_FOR_RBG_TO_YUV=%d", useHwcForRgbToYuv);
     StringAppendF(&result, " MAX_VIRT_DISPLAY_DIM=%zu",
                   getHwComposer().getMaxVirtualDisplayDimension());
-    StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !mConfig->hasSyncFramework);
+    StringAppendF(&result, " RUNNING_WITHOUT_SYNC_FRAMEWORK=%d", !hasSyncFramework);
     StringAppendF(&result, " NUM_FRAMEBUFFER_SURFACE_BUFFERS=%" PRId64,
-                  mConfig->maxFrameBufferAcquiredBuffers);
+                  maxFrameBufferAcquiredBuffers);
     result.append("]");
 }
 
@@ -5767,7 +5884,7 @@
     StringAppendF(&result,
                   "         present offset: %9" PRId64 " ns\t        VSYNC period: %9" PRId64
                   " ns\n\n",
-                  mConfig->dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
+                  dispSyncPresentTimeOffset, getVsyncPeriodFromHWC());
 }
 
 void SurfaceFlinger::dumpEvents(std::string& result) const {
@@ -5866,7 +5983,7 @@
 }
 
 void SurfaceFlinger::dumpWideColorInfo(std::string& result) const {
-    StringAppendF(&result, "Device supports wide color: %d\n", mConfig->supportsWideColor);
+    StringAppendF(&result, "Device supports wide color: %d\n", mSupportsWideColor);
     StringAppendF(&result, "Device uses color management: %d\n", useColorManagement);
     StringAppendF(&result, "DisplayColorSetting: %s\n",
                   decodeDisplayColorSetting(mDisplayColorSetting).c_str());
@@ -5900,7 +6017,7 @@
         }
     }
 
-    if (mConfig->legacyFrontEndEnabled) {
+    if (mLegacyFrontEndEnabled) {
         LayersProto layersProto;
         for (const sp<Layer>& layer : mDrawingState.layersSortedByZ) {
             if (stackIdsToSkip.find(layer->getLayerStack().id) != stackIdsToSkip.end()) {
@@ -6557,7 +6674,7 @@
                         if (!validateCompositionDataspace(dataspace)) {
                             return BAD_VALUE;
                         }
-                        mOverrideDefaultCompositionDataspace = dataspace;
+                        mDefaultCompositionDataspace = dataspace;
                     }
                     n = data.readInt32();
                     if (n) {
@@ -6565,12 +6682,12 @@
                         if (!validateCompositionDataspace(dataspace)) {
                             return BAD_VALUE;
                         }
-                        mOverrideWideColorGamutCompositionDataspace = dataspace;
+                        mWideColorGamutCompositionDataspace = dataspace;
                     }
                 } else {
-                    // Reset data space overrides.
-                    mOverrideDefaultCompositionDataspace.reset();
-                    mOverrideWideColorGamutCompositionDataspace.reset();
+                    // restore composition data space.
+                    mDefaultCompositionDataspace = defaultCompositionDataspace;
+                    mWideColorGamutCompositionDataspace = wideColorGamutCompositionDataspace;
                 }
                 return NO_ERROR;
             }
@@ -6709,10 +6826,10 @@
                     }
                     {
                         Mutex::Autolock lock(mStateLock);
-                        mConfig->layerCachingEnabled = n != 0;
+                        mLayerCachingEnabled = n != 0;
                         for (const auto& [_, display] : mDisplays) {
                             if (!inputId || *inputId == display->getPhysicalId()) {
-                                display->enableLayerCaching(mConfig->layerCachingEnabled);
+                                display->enableLayerCaching(mLayerCachingEnabled);
                             }
                         }
                     }
@@ -7037,7 +7154,7 @@
     });
 
     GetLayerSnapshotsFunction getLayerSnapshots;
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         getLayerSnapshots =
                 getLayerSnapshotsForScreenshots(layerStack, args.uid, std::move(excludeLayerIds));
     } else {
@@ -7080,7 +7197,7 @@
     });
 
     GetLayerSnapshotsFunction getLayerSnapshots;
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         getLayerSnapshots = getLayerSnapshotsForScreenshots(layerStack, CaptureArgs::UNSET_UID,
                                                             /*snapshotFilterFn=*/nullptr);
     } else {
@@ -7176,7 +7293,7 @@
     RenderAreaFuture renderAreaFuture = ftl::defer([=]() -> std::unique_ptr<RenderArea> {
         ui::Transform layerTransform;
         Rect layerBufferSize;
-        if (mConfig->layerLifecycleManagerEnabled) {
+        if (mLayerLifecycleManagerEnabled) {
             frontend::LayerSnapshot* snapshot =
                     mLayerSnapshotBuilder.getSnapshot(parent->getSequence());
             if (!snapshot) {
@@ -7196,7 +7313,7 @@
                                                  args.hintForSeamlessTransition);
     });
     GetLayerSnapshotsFunction getLayerSnapshots;
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         std::optional<FloatRect> parentCrop = std::nullopt;
         if (args.childrenOnly) {
             parentCrop = crop.isEmpty() ? FloatRect(0, 0, reqSize.width, reqSize.height)
@@ -7449,7 +7566,7 @@
                     layerStack, regionSampling, renderArea = std::move(renderArea),
                     renderIntent]() -> FenceResult {
         std::unique_ptr<compositionengine::CompositionEngine> compositionEngine =
-                mConfig->factory->createCompositionEngine();
+                mFactory.createCompositionEngine();
         compositionEngine->setRenderEngine(mRenderEngine.get());
 
         compositionengine::Output::ColorProfile colorProfile{.dataspace = dataspace,
@@ -7519,7 +7636,7 @@
 }
 
 void SurfaceFlinger::traverseLegacyLayers(const LayerVector::Visitor& visitor) const {
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         for (auto& layer : mLegacyLayers) {
             visitor(layer.second.get());
         }
@@ -7841,7 +7958,9 @@
             }
 
             if (const auto device = getDisplayDeviceLocked(id)) {
-                device->enableRefreshRateOverlay(enable, setByHwc);
+                device->enableRefreshRateOverlay(enable, setByHwc, mRefreshRateOverlaySpinner,
+                                                 mRefreshRateOverlayRenderRate,
+                                                 mRefreshRateOverlayShowInMiddle);
             }
         }
     }
@@ -7852,12 +7971,12 @@
 }
 
 int SurfaceFlinger::calculateMaxAcquiredBufferCount(Fps refreshRate,
-                                                    std::chrono::nanoseconds presentLatency) const {
+                                                    std::chrono::nanoseconds presentLatency) {
     auto pipelineDepth = presentLatency.count() / refreshRate.getPeriodNsecs();
     if (presentLatency.count() % refreshRate.getPeriodNsecs()) {
         pipelineDepth++;
     }
-    return std::max(mConfig->minAcquiredBuffers, static_cast<int64_t>(pipelineDepth - 1));
+    return std::max(minAcquiredBuffers, static_cast<int64_t>(pipelineDepth - 1));
 }
 
 status_t SurfaceFlinger::getMaxAcquiredBufferCount(int* buffers) const {
@@ -7939,7 +8058,7 @@
 }
 
 void SurfaceFlinger::sample() {
-    if (!mConfig->lumaSampling || !mRegionSamplingThread) {
+    if (!mLumaSampling || !mRegionSamplingThread) {
         return;
     }
 
@@ -8131,7 +8250,7 @@
 void SurfaceFlinger::moveSnapshotsFromCompositionArgs(
         compositionengine::CompositionRefreshArgs& refreshArgs,
         const std::vector<std::pair<Layer*, LayerFE*>>& layers) {
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         std::vector<std::unique_ptr<frontend::LayerSnapshot>>& snapshots =
                 mLayerSnapshotBuilder.getSnapshots();
         for (auto [_, layerFE] : layers) {
@@ -8139,7 +8258,7 @@
             snapshots[i] = std::move(layerFE->mSnapshot);
         }
     }
-    if (mConfig->legacyFrontEndEnabled && !mConfig->layerLifecycleManagerEnabled) {
+    if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) {
         for (auto [layer, layerFE] : layers) {
             layer->updateLayerSnapshot(std::move(layerFE->mSnapshot));
         }
@@ -8149,7 +8268,7 @@
 std::vector<std::pair<Layer*, LayerFE*>> SurfaceFlinger::moveSnapshotsToCompositionArgs(
         compositionengine::CompositionRefreshArgs& refreshArgs, bool cursorOnly) {
     std::vector<std::pair<Layer*, LayerFE*>> layers;
-    if (mConfig->layerLifecycleManagerEnabled) {
+    if (mLayerLifecycleManagerEnabled) {
         nsecs_t currentTime = systemTime();
         mLayerSnapshotBuilder.forEachVisibleSnapshot(
                 [&](std::unique_ptr<frontend::LayerSnapshot>& snapshot) {
@@ -8175,7 +8294,7 @@
                     layers.emplace_back(legacyLayer.get(), layerFE.get());
                 });
     }
-    if (mConfig->legacyFrontEndEnabled && !mConfig->layerLifecycleManagerEnabled) {
+    if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) {
         auto moveSnapshots = [&layers, &refreshArgs, cursorOnly](Layer* layer) {
             if (const auto& layerFE = layer->getCompositionEngineLayerFE()) {
                 if (cursorOnly &&
@@ -8267,7 +8386,7 @@
                      .displays = mFrontEndDisplayInfos,
                      .displayChanges = true,
                      .globalShadowSettings = mDrawingState.globalShadowSettings,
-                     .supportsBlur = mConfig->supportsBlur,
+                     .supportsBlur = mSupportsBlur,
                      .forceFullDamage = mForceFullDamage,
                      .excludeLayerIds = std::move(excludeLayerIds),
                      .supportedLayerGenericMetadata =
@@ -8301,7 +8420,7 @@
                      .displays = mFrontEndDisplayInfos,
                      .displayChanges = true,
                      .globalShadowSettings = mDrawingState.globalShadowSettings,
-                     .supportsBlur = mConfig->supportsBlur,
+                     .supportsBlur = mSupportsBlur,
                      .forceFullDamage = mForceFullDamage,
                      .parentCrop = parentCrop,
                      .excludeLayerIds = std::move(excludeLayerIds),
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 55e1b75..5c57abd 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -63,7 +63,6 @@
 #include <scheduler/interface/ICompositor.h>
 #include <ui/FenceResult.h>
 
-#include "Client.h"
 #include "Display/PhysicalDisplay.h"
 #include "DisplayDevice.h"
 #include "DisplayHardware/HWC2.h"
@@ -82,7 +81,6 @@
 #include "Scheduler/RefreshRateSelector.h"
 #include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
-#include "SurfaceFlingerConfig.h"
 #include "SurfaceFlingerFactory.h"
 #include "ThreadContext.h"
 #include "Tracing/LayerTracing.h"
@@ -109,6 +107,7 @@
 
 #include <aidl/android/hardware/graphics/common/DisplayDecorationSupport.h>
 #include <aidl/android/hardware/graphics/composer3/RefreshRateChangedDebugData.h>
+#include "Client.h"
 
 using namespace android::surfaceflinger;
 
@@ -198,7 +197,10 @@
                        private scheduler::ISchedulerCallback,
                        private compositionengine::ICEPowerCallback {
 public:
-    explicit SurfaceFlinger(surfaceflinger::Config&) ANDROID_API;
+    struct SkipInitializationTag {};
+
+    SurfaceFlinger(surfaceflinger::Factory&, SkipInitializationTag) ANDROID_API;
+    explicit SurfaceFlinger(surfaceflinger::Factory&) ANDROID_API;
 
     // set main thread scheduling policy
     static status_t setSchedFifo(bool enabled) ANDROID_API;
@@ -208,9 +210,51 @@
 
     static char const* getServiceName() ANDROID_API { return "SurfaceFlinger"; }
 
+    // If fences from sync Framework are supported.
+    static bool hasSyncFramework;
+
+    // The offset in nanoseconds to use when VsyncController timestamps present fence
+    // signaling time.
+    static int64_t dispSyncPresentTimeOffset;
+
+    // Some hardware can do RGB->YUV conversion more efficiently in hardware
+    // controlled by HWC than in hardware controlled by the video encoder.
+    // This instruct VirtualDisplaySurface to use HWC for such conversion on
+    // GL composition.
+    static bool useHwcForRgbToYuv;
+
+    // Controls the number of buffers SurfaceFlinger will allocate for use in
+    // FramebufferSurface
+    static int64_t maxFrameBufferAcquiredBuffers;
+
+    // Controls the minimum acquired buffers SurfaceFlinger will suggest via
+    // ISurfaceComposer.getMaxAcquiredBufferCount().
+    static int64_t minAcquiredBuffers;
+
+    // Controls the maximum width and height in pixels that the graphics pipeline can support for
+    // GPU fallback composition. For example, 8k devices with 4k GPUs, or 4k devices with 2k GPUs.
+    static uint32_t maxGraphicsWidth;
+    static uint32_t maxGraphicsHeight;
+
     // Indicate if device wants color management on its display.
     static const constexpr bool useColorManagement = true;
 
+    static bool useContextPriority;
+
+    // The data space and pixel format that SurfaceFlinger expects hardware composer
+    // to composite efficiently. Meaning under most scenarios, hardware composer
+    // will accept layers with the data space and pixel format.
+    static ui::Dataspace defaultCompositionDataspace;
+    static ui::PixelFormat defaultCompositionPixelFormat;
+
+    // The data space and pixel format that SurfaceFlinger expects hardware composer
+    // to composite efficiently for wide color gamut surfaces. Meaning under most scenarios,
+    // hardware composer will accept layers with the data space and pixel format.
+    static ui::Dataspace wideColorGamutCompositionDataspace;
+    static ui::PixelFormat wideColorGamutCompositionPixelFormat;
+
+    static constexpr SkipInitializationTag SkipInitialization;
+
     static LatchUnsignaledConfig enableLatchUnsignaledConfig;
 
     // must be called before clients can connect
@@ -231,8 +275,7 @@
     // Schedule sampling independently from commit or composite.
     void scheduleSample();
 
-    const surfaceflinger::Config& getConfig() { return *mConfig; }
-    surfaceflinger::Factory& getFactory() { return *mConfig->factory; }
+    surfaceflinger::Factory& getFactory() { return mFactory; }
 
     // The CompositionEngine encapsulates all composition related interfaces and actions.
     compositionengine::CompositionEngine& getCompositionEngine() const;
@@ -264,6 +307,10 @@
         return mTransactionCallbackInvoker;
     }
 
+    // If set, disables reusing client composition buffers. This can be set by
+    // debug.sf.disable_client_composition_cache
+    bool mDisableClientCompositionCache = false;
+
     // Disables expensive rendering for all displays
     // This is scheduled on the main thread
     void disableExpensiveRendering();
@@ -274,6 +321,17 @@
     // run parallel to the hwc validateDisplay call and re-run if the predition is incorrect.
     bool mPredictCompositionStrategy = false;
 
+    // If true, then any layer with a SMPTE 170M transfer function is decoded using the sRGB
+    // transfer instead. This is mainly to preserve legacy behavior, where implementations treated
+    // SMPTE 170M as sRGB prior to color management being implemented, and now implementations rely
+    // on this behavior to increase contrast for some media sources.
+    bool mTreat170mAsSrgb = false;
+
+    // Allows to ignore physical orientation provided through hwc API in favour of
+    // 'ro.surface_flinger.primary_display_orientation'.
+    // TODO(b/246793311): Clean up a temporary property
+    bool mIgnoreHwcPhysicalDisplayOrientation = false;
+
     void forceFutureUpdate(int delayInMs);
     const DisplayDevice* getDisplayFromLayerStack(ui::LayerStack)
             REQUIRES(mStateLock, kMainThreadContext);
@@ -608,6 +666,12 @@
     // Keeps track of whether the kernel idle timer is currently enabled, so we don't have to
     // make calls to sys prop each time.
     bool mKernelIdleTimerEnabled = false;
+    // Show spinner with refresh rate overlay
+    bool mRefreshRateOverlaySpinner = false;
+    // Show render rate with refresh rate overlay
+    bool mRefreshRateOverlayRenderRate = false;
+    // Show render rate overlay offseted to the middle of the screen (e.g. for circular displays)
+    bool mRefreshRateOverlayShowInMiddle = false;
 
     void setDesiredActiveMode(display::DisplayModeRequest&&, bool force = false)
             REQUIRES(mStateLock);
@@ -1042,8 +1106,8 @@
      */
     const std::unordered_map<std::string, uint32_t>& getGenericLayerMetadataKeyMap() const;
 
-    int calculateMaxAcquiredBufferCount(Fps refreshRate,
-                                        std::chrono::nanoseconds presentLatency) const;
+    static int calculateMaxAcquiredBufferCount(Fps refreshRate,
+                                               std::chrono::nanoseconds presentLatency);
     int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
 
     bool isHdrLayer(const frontend::LayerSnapshot& snapshot) const;
@@ -1053,7 +1117,8 @@
     void traverseLegacyLayers(const LayerVector::Visitor& visitor) const;
 
     sp<StartPropertySetThread> mStartPropertySetThread;
-    surfaceflinger::Config* const mConfig = nullptr;
+    surfaceflinger::Factory& mFactory;
+    pid_t mPid;
     std::future<void> mRenderEnginePrimeCacheFuture;
 
     // mStateLock has conventions related to the current thread, because only
@@ -1080,6 +1145,12 @@
     float mGlobalSaturationFactor = 1.0f;
     mat4 mClientColorMatrix;
 
+    size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
+    // If there are more GraphicBufferProducers tracked by SurfaceFlinger than
+    // this threshold, then begin logging.
+    size_t mGraphicBufferProducerListSizeLogThreshold =
+            static_cast<size_t>(0.95 * static_cast<double>(MAX_LAYERS));
+
     // protected by mStateLock (but we could use another lock)
     bool mLayersRemoved = false;
     bool mLayersAdded = false;
@@ -1089,6 +1160,7 @@
 
     // constant members (no synchronization needed for access)
     const nsecs_t mBootTime = systemTime();
+    bool mIsUserBuild = true;
 
     // Can only accessed from the main thread, these members
     // don't need synchronization
@@ -1100,6 +1172,7 @@
     // Used to ensure we omit a callback when HDR layer info listener is newly added but the
     // scene hasn't changed
     bool mAddingHDRLayerInfoListener = false;
+    bool mIgnoreHdrCameraLayers = false;
 
     // Set during transaction application stage to track if the input info or children
     // for a layer has changed.
@@ -1158,6 +1231,9 @@
     std::atomic<nsecs_t> mDebugInTransaction = 0;
     std::atomic_bool mForceFullDamage = false;
 
+    bool mLayerCachingEnabled = false;
+    bool mBackpressureGpuComposition = false;
+
     LayerTracing mLayerTracing;
     bool mLayerTracingEnabled = false;
 
@@ -1170,6 +1246,9 @@
 
     VsyncId mLastCommittedVsyncId;
 
+    // If blurs should be enabled on this device.
+    bool mSupportsBlur = false;
+
     TransactionCallbackInvoker mTransactionCallbackInvoker;
 
     // We maintain a pool of pre-generated texture names to hand out to avoid
@@ -1201,9 +1280,13 @@
     // This property can be used to force SurfaceFlinger to always pick a certain color mode.
     ui::ColorMode mForceColorMode = ui::ColorMode::NATIVE;
 
-    std::optional<ui::Dataspace> mOverrideDefaultCompositionDataspace;
-    std::optional<ui::Dataspace> mOverrideWideColorGamutCompositionDataspace;
+    // Whether to enable wide color gamut (e.g. Display P3) for internal displays that support it.
+    // If false, wide color modes are filtered out for all internal displays.
+    bool mSupportsWideColor = false;
 
+    ui::Dataspace mDefaultCompositionDataspace;
+    ui::Dataspace mWideColorGamutCompositionDataspace;
+    ui::Dataspace mColorSpaceAgnosticDataspace;
     float mDimmingRatio = -1.f;
 
     std::unique_ptr<renderengine::RenderEngine> mRenderEngine;
@@ -1217,6 +1300,8 @@
     // any mutex.
     size_t mMaxRenderTargetSize{1};
 
+    const std::string mHwcServiceName;
+
     /*
      * Scheduler
      */
@@ -1233,9 +1318,14 @@
     // below flags are set by main thread only
     bool mSetActiveModePending = false;
 
+    bool mLumaSampling = true;
     sp<RegionSamplingThread> mRegionSamplingThread;
     sp<FpsReporter> mFpsReporter;
     sp<TunnelModeEnabledReporter> mTunnelModeEnabledReporter;
+    ui::DisplayPrimaries mInternalDisplayPrimaries;
+
+    const float mEmulatedDisplayDensity;
+    const float mInternalDisplayDensity;
 
     // Should only be accessed by the main thread.
     sp<os::IInputFlinger> mInputFlinger;
@@ -1312,6 +1402,9 @@
 
     bool mPowerHintSessionEnabled;
 
+    bool mLayerLifecycleManagerEnabled = false;
+    bool mLegacyFrontEndEnabled = true;
+
     frontend::LayerLifecycleManager mLayerLifecycleManager;
     frontend::LayerHierarchyBuilder mLayerHierarchyBuilder{{}};
     frontend::LayerSnapshotBuilder mLayerSnapshotBuilder;
diff --git a/services/surfaceflinger/SurfaceFlingerConfig.cpp b/services/surfaceflinger/SurfaceFlingerConfig.cpp
deleted file mode 100644
index 0b25a44..0000000
--- a/services/surfaceflinger/SurfaceFlingerConfig.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2023 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 <cstdlib>
-
-#include <SurfaceFlingerProperties.h>
-#include <SurfaceFlingerProperties.sysprop.h>
-#include <android-base/properties.h>
-#include <android/configuration.h>
-
-#include "SurfaceFlingerConfig.h"
-
-namespace android::surfaceflinger {
-
-using namespace std::string_literals;
-
-namespace {
-
-// TODO(b/141333600): Consolidate with DisplayMode::Builder::getDefaultDensity.
-constexpr float FALLBACK_DENSITY = ACONFIGURATION_DENSITY_TV;
-
-float getDensityFromProperty(const std::string& key, bool required) {
-    std::string value = base::GetProperty(key, ""s);
-    const float density = static_cast<float>(std::atof(value.c_str()));
-    if (density == 0.f && required) {
-        ALOGE("%s must be defined as a build property", key.c_str());
-        return FALLBACK_DENSITY;
-    }
-    return density;
-}
-
-} // namespace
-
-Config::Config() = default;
-
-Config Config::makeDefault(Factory* factory) {
-    Config cfg{};
-
-    // Note: The values set here will affect tests.
-    // To keep tests hermetic, do not set values here based on runtime values.
-
-    cfg.factory = factory;
-    cfg.hwcServiceName = "default"s;
-    cfg.pid = getpid(); // Exception to the hermetic rules. Allow the pid to be cached.
-
-    return cfg;
-}
-
-Config Config::makeProduction(Factory* factory) {
-    Config cfg = makeDefault(factory);
-
-    cfg.hwcServiceName = base::GetProperty("debug.sf.hwc_service_name"s, "default"s);
-
-    cfg.emulatedDisplayDensity = getDensityFromProperty("qemu.sf.lcd_density"s, false),
-    cfg.internalDisplayDensity =
-            getDensityFromProperty("ro.sf.lcd_density"s, cfg.emulatedDisplayDensity == 0.f),
-
-    cfg.hasSyncFramework = sysprop::running_without_sync_framework(cfg.hasSyncFramework);
-    cfg.dispSyncPresentTimeOffset =
-            sysprop::present_time_offset_from_vsync_ns(cfg.dispSyncPresentTimeOffset);
-    cfg.useHwcForRgbToYuv = sysprop::force_hwc_copy_for_virtual_displays(cfg.useHwcForRgbToYuv);
-    cfg.maxFrameBufferAcquiredBuffers =
-            sysprop::max_frame_buffer_acquired_buffers(cfg.maxFrameBufferAcquiredBuffers);
-    cfg.minAcquiredBuffers = sysprop::SurfaceFlingerProperties::min_acquired_buffers().value_or(
-            cfg.minAcquiredBuffers);
-
-    cfg.maxGraphicsWidth = std::max(static_cast<uint32_t>(sysprop::max_graphics_width(
-                                            static_cast<int32_t>(cfg.maxGraphicsWidth))),
-                                    0u);
-    cfg.maxGraphicsHeight = std::max(static_cast<uint32_t>(sysprop::max_graphics_height(
-                                             static_cast<int32_t>(cfg.maxGraphicsHeight))),
-                                     0u);
-
-    cfg.supportsWideColor = sysprop::has_wide_color_display(cfg.supportsWideColor);
-
-    cfg.defaultCompositionDataspace = static_cast<ui::Dataspace>(
-            sysprop::default_composition_dataspace(cfg.defaultCompositionDataspace));
-    cfg.defaultCompositionPixelFormat = static_cast<ui::PixelFormat>(
-            sysprop::default_composition_pixel_format(cfg.defaultCompositionPixelFormat));
-
-    cfg.wideColorGamutCompositionDataspace =
-            static_cast<ui::Dataspace>(sysprop::wcg_composition_dataspace(
-                    cfg.supportsWideColor ? ui::Dataspace::DISPLAY_P3 : ui::Dataspace::V0_SRGB));
-    cfg.wideColorGamutCompositionPixelFormat = static_cast<ui::PixelFormat>(
-            sysprop::wcg_composition_pixel_format(cfg.wideColorGamutCompositionPixelFormat));
-
-    cfg.colorSpaceAgnosticDataspace = static_cast<ui::Dataspace>(
-            sysprop::color_space_agnostic_dataspace(cfg.colorSpaceAgnosticDataspace));
-
-    cfg.internalDisplayPrimaries = sysprop::getDisplayNativePrimaries();
-
-    cfg.layerCachingEnabled =
-            base::GetBoolProperty("debug.sf.enable_layer_caching"s,
-                                  android::sysprop::SurfaceFlingerProperties::enable_layer_caching()
-                                          .value_or(cfg.layerCachingEnabled));
-    cfg.useContextPriority = sysprop::use_context_priority(cfg.useContextPriority);
-
-    cfg.isUserBuild = "user"s == base::GetProperty("ro.build.type"s, "user"s);
-
-    cfg.backpressureGpuComposition = base::GetBoolProperty("debug.sf.enable_gl_backpressure"s,
-                                                           cfg.backpressureGpuComposition);
-    cfg.supportsBlur =
-            base::GetBoolProperty("ro.surface_flinger.supports_background_blur"s, cfg.supportsBlur);
-
-    cfg.lumaSampling = base::GetBoolProperty("debug.sf.luma_sampling"s, cfg.lumaSampling);
-
-    cfg.disableClientCompositionCache =
-            base::GetBoolProperty("debug.sf.disable_client_composition_cache"s,
-                                  cfg.disableClientCompositionCache);
-
-    cfg.predictCompositionStrategy =
-            base::GetBoolProperty("debug.sf.predict_hwc_composition_strategy"s,
-                                  cfg.predictCompositionStrategy);
-
-    cfg.treat170mAsSrgb =
-            base::GetBoolProperty("debug.sf.treat_170m_as_sRGB"s, cfg.treat170mAsSrgb);
-
-    cfg.ignoreHwcPhysicalDisplayOrientation =
-            base::GetBoolProperty("debug.sf.ignore_hwc_physical_display_orientation"s,
-                                  cfg.ignoreHwcPhysicalDisplayOrientation);
-
-    cfg.trebleTestingOverride =
-            base::GetBoolProperty("debug.sf.treble_testing_override"s, cfg.trebleTestingOverride);
-
-    // TODO (b/270966065) Update the HWC based refresh rate overlay to support spinner
-    cfg.refreshRateOverlay.showSpinner =
-            base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_spinner"s,
-                                  cfg.refreshRateOverlay.showSpinner);
-    cfg.refreshRateOverlay.showRenderRate =
-            base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_render_rate"s,
-                                  cfg.refreshRateOverlay.showRenderRate);
-    cfg.refreshRateOverlay.showInMiddle =
-            base::GetBoolProperty("debug.sf.show_refresh_rate_overlay_in_middle"s,
-                                  cfg.refreshRateOverlay.showInMiddle);
-
-    cfg.ignoreHdrCameraLayers = sysprop::ignore_hdr_camera_layers(cfg.ignoreHdrCameraLayers);
-
-    cfg.enableTransactionTracing = base::GetBoolProperty("debug.sf.enable_transaction_tracing"s,
-                                                         cfg.enableTransactionTracing);
-    cfg.layerLifecycleManagerEnabled =
-            base::GetBoolProperty("persist.debug.sf.enable_layer_lifecycle_manager"s,
-                                  cfg.layerLifecycleManagerEnabled);
-    cfg.legacyFrontEndEnabled = !cfg.layerLifecycleManagerEnabled ||
-            base::GetBoolProperty("persist.debug.sf.enable_legacy_frontend"s, false);
-
-    return cfg;
-}
-
-} // namespace android::surfaceflinger
\ No newline at end of file
diff --git a/services/surfaceflinger/SurfaceFlingerConfig.h b/services/surfaceflinger/SurfaceFlingerConfig.h
deleted file mode 100644
index 7c3348e..0000000
--- a/services/surfaceflinger/SurfaceFlingerConfig.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2023 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 <cstdlib>
-
-#include <ui/ConfigStoreTypes.h>
-#include <ui/GraphicTypes.h>
-
-namespace android::surfaceflinger {
-
-class Factory;
-
-struct Config final {
-    Factory* factory = nullptr;
-
-    std::string hwcServiceName;
-    pid_t pid;
-
-    float emulatedDisplayDensity = 0;
-    float internalDisplayDensity = 0;
-
-    // If fences from sync Framework are supported.
-    bool hasSyncFramework = true;
-
-    // The offset in nanoseconds to use when VsyncController timestamps present
-    // fence signaling time.
-    int64_t dispSyncPresentTimeOffset = 0;
-
-    // Some hardware can do RGB->YUV conversion more efficiently in hardware
-    // controlled by HWC than in hardware controlled by the video encoder. This
-    // instruct VirtualDisplaySurface to use HWC for such conversion on GL
-    // composition.
-    bool useHwcForRgbToYuv = false;
-
-    // Controls the number of buffers SurfaceFlinger will allocate for use in
-    // FramebufferSurface
-    int64_t maxFrameBufferAcquiredBuffers = 2;
-
-    // Controls the minimum acquired buffers SurfaceFlinger will suggest via
-    // ISurfaceComposer.getMaxAcquiredBufferCount().
-    int64_t minAcquiredBuffers = 1;
-
-    // Controls the maximum width and height in pixels that the graphics
-    // pipeline can support for GPU fallback composition. For example, 8k
-    // devices with 4k GPUs, or 4k devices with 2k GPUs.
-    uint32_t maxGraphicsWidth = 0;
-    uint32_t maxGraphicsHeight = 0;
-
-    // Whether to enable wide color gamut (e.g. Display P3) for internal
-    // displays that support it. If false, wide color modes are filtered out
-    // for all internal displays.
-    bool mSupportsWideColor = false;
-    bool supportsWideColor = false;
-
-    // The data space and pixel format that SurfaceFlinger expects hardware
-    // composer to composite efficiently. Meaning under most scenarios,
-    // hardware composer will accept layers with the data space and pixel
-    // format.
-    ui::Dataspace defaultCompositionDataspace = ui::Dataspace::V0_SRGB;
-    ui::PixelFormat defaultCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
-
-    // The data space and pixel format that SurfaceFlinger expects hardware
-    // composer to composite efficiently for wide color gamut surfaces. Meaning
-    // under most scenarios, hardware composer will accept layers with the data
-    // space and pixel format.
-    ui::Dataspace wideColorGamutCompositionDataspace = ui::Dataspace::V0_SRGB;
-    ui::PixelFormat wideColorGamutCompositionPixelFormat = ui::PixelFormat::RGBA_8888;
-
-    ui::Dataspace colorSpaceAgnosticDataspace = ui::Dataspace::UNKNOWN;
-
-    ui::DisplayPrimaries internalDisplayPrimaries{};
-
-    bool layerCachingEnabled = false;
-    bool useContextPriority = true;
-    bool isUserBuild = true;
-    bool backpressureGpuComposition = true;
-
-    // If blurs should be enabled on this device.
-    bool supportsBlur = false;
-    bool lumaSampling = true;
-
-    // If set, disables reusing client composition buffers. This can be set by
-    // debug.sf.disable_client_composition_cache
-    bool disableClientCompositionCache = false;
-
-    // If set, composition engine tries to predict the composition strategy
-    // provided by HWC based on the previous frame. If the strategy can be
-    // predicted, gpu composition will run parallel to the hwc validateDisplay
-    // call and re-run if the predition is incorrect.
-    bool predictCompositionStrategy = true;
-
-    // If true, then any layer with a SMPTE 170M transfer function is decoded
-    // using the sRGB transfer instead. This is mainly to preserve legacy
-    // behavior, where implementations treated SMPTE 170M as sRGB prior to
-    // color management being implemented, and now implementations rely on this
-    // behavior to increase contrast for some media sources.
-    bool treat170mAsSrgb = false;
-
-    // Allows to ignore physical orientation provided through hwc API in favour
-    // of 'ro.surface_flinger.primary_display_orientation'.
-    // TODO(b/246793311): Clean up a temporary property
-    bool ignoreHwcPhysicalDisplayOrientation = false;
-
-    bool trebleTestingOverride = false;
-
-    struct {
-        // Show spinner with refresh rate overlay
-        bool showSpinner = false;
-
-        // Show render rate with refresh rate overlay
-        bool showRenderRate = false;
-
-        // Show render rate overlay offseted to the middle of the screen (e.g.
-        // for circular displays)
-        bool showInMiddle = false;
-    } refreshRateOverlay;
-
-    bool ignoreHdrCameraLayers = false;
-    bool enableTransactionTracing = true;
-    bool layerLifecycleManagerEnabled = false;
-    bool legacyFrontEndEnabled = true;
-
-    static Config makeDefault(Factory* factory);
-    static Config makeProduction(Factory* factory);
-
-private:
-    Config();
-};
-
-} // namespace android::surfaceflinger
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.cpp b/services/surfaceflinger/SurfaceFlingerFactory.cpp
index ac351cb..7bd6cf6 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerFactory.cpp
@@ -14,17 +14,22 @@
  * limitations under the License.
  */
 
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wconversion"
+
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerConfig.h"
 #include "SurfaceFlingerDefaultFactory.h"
 
 namespace android::surfaceflinger {
 
 sp<SurfaceFlinger> createSurfaceFlinger() {
     static DefaultFactory factory;
-    static Config config = Config::makeProduction(&factory);
 
-    return sp<SurfaceFlinger>::make(config);
+    return sp<SurfaceFlinger>::make(factory);
 }
 
 } // namespace android::surfaceflinger
+
+// TODO(b/129481165): remove the #pragma below and fix conversion issues
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
index d296c47..9fac14e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_displayhardware_fuzzer.cpp
@@ -481,8 +481,7 @@
 
     sp<FramebufferSurface> surface =
             sp<FramebufferSurface>::make(mHwc, mPhysicalDisplayId, bqConsumer,
-                                         getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/,
-                                         mFdp.PickValueInArray(kMaxFrameBufferAcquiredBuffers));
+                                         getFuzzedSize() /*size*/, getFuzzedSize() /*maxSize*/);
     surface->beginFrame(mFdp.ConsumeBool());
 
     surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
@@ -516,8 +515,7 @@
 
     auto surface =
             sp<VirtualDisplaySurface>::make(mHwc, VirtualDisplayId, sink, bqProducer, bqConsumer,
-                                            mFdp.ConsumeRandomLengthString().c_str() /*name*/,
-                                            mFdp.ConsumeBool() /* useHwcForRgbToYuv */);
+                                            mFdp.ConsumeRandomLengthString().c_str() /*name*/);
 
     surface->beginFrame(mFdp.ConsumeBool());
     surface->prepareFrame(mFdp.PickValueInArray(kCompositionTypes));
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index df342dc..80943b5 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -124,20 +124,19 @@
     mFlinger->setSchedFifo(mFdp.ConsumeBool());
     mFlinger->setSchedAttr(mFdp.ConsumeBool());
     mFlinger->getServiceName();
+    mFlinger->hasSyncFramework = mFdp.ConsumeBool();
+    mFlinger->dispSyncPresentTimeOffset = mFdp.ConsumeIntegral<int64_t>();
+    mFlinger->useHwcForRgbToYuv = mFdp.ConsumeBool();
+    mFlinger->maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral<int64_t>();
+    mFlinger->maxGraphicsWidth = mFdp.ConsumeIntegral<uint32_t>();
+    mFlinger->maxGraphicsHeight = mFdp.ConsumeIntegral<uint32_t>();
+    mTestableFlinger.mutableSupportsWideColor() = mFdp.ConsumeBool();
+    mFlinger->useContextPriority = mFdp.ConsumeBool();
 
-    auto& config = mTestableFlinger.mutableConfig();
-    config.hasSyncFramework = mFdp.ConsumeBool();
-    config.dispSyncPresentTimeOffset = mFdp.ConsumeIntegral<int64_t>();
-    config.useHwcForRgbToYuv = mFdp.ConsumeBool();
-    config.maxFrameBufferAcquiredBuffers = mFdp.ConsumeIntegral<int64_t>();
-    config.maxGraphicsWidth = mFdp.ConsumeIntegral<uint32_t>();
-    config.maxGraphicsHeight = mFdp.ConsumeIntegral<uint32_t>();
-    config.supportsWideColor = mFdp.ConsumeBool();
-    config.useContextPriority = mFdp.ConsumeBool();
-    config.defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
-    config.defaultCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats);
-    config.wideColorGamutCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
-    config.wideColorGamutCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats);
+    mFlinger->defaultCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
+    mFlinger->defaultCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats);
+    mFlinger->wideColorGamutCompositionDataspace = mFdp.PickValueInArray(kDataspaces);
+    mFlinger->wideColorGamutCompositionPixelFormat = mFdp.PickValueInArray(kPixelFormats);
 
     mFlinger->enableLatchUnsignaledConfig = mFdp.PickValueInArray(kLatchUnsignaledConfig);
 
@@ -156,7 +155,7 @@
 }
 
 void SurfaceFlingerFuzzer::setInternalDisplayPrimaries() {
-    auto& primaries = mTestableFlinger.mutableConfig().internalDisplayPrimaries;
+    ui::DisplayPrimaries primaries;
     primaries.red.X = mFdp.ConsumeFloatingPoint<float>();
     primaries.red.Y = mFdp.ConsumeFloatingPoint<float>();
     primaries.red.Z = mFdp.ConsumeFloatingPoint<float>();
@@ -169,6 +168,7 @@
     primaries.white.X = mFdp.ConsumeFloatingPoint<float>();
     primaries.white.Y = mFdp.ConsumeFloatingPoint<float>();
     primaries.white.Z = mFdp.ConsumeFloatingPoint<float>();
+    mTestableFlinger.setInternalDisplayPrimaries(primaries);
 }
 
 void SurfaceFlingerFuzzer::setTransactionState() {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 97cb5d3..0c9a16b 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -46,7 +46,6 @@
 #include "Scheduler/VsyncModulator.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerConfig.h"
 #include "SurfaceFlingerDefaultFactory.h"
 #include "ThreadContext.h"
 #include "TimeStats/TimeStats.h"
@@ -151,8 +150,6 @@
                                                     ui::PixelFormat::YCBCR_P010,
                                                     ui::PixelFormat::HSV_888};
 
-static constexpr int kMaxFrameBufferAcquiredBuffers[] = {2, 3, 4};
-
 inline VsyncId getFuzzedVsyncId(FuzzedDataProvider& fdp) {
     return VsyncId{fdp.ConsumeIntegral<int64_t>()};
 }
@@ -407,8 +404,6 @@
     SurfaceFlinger *flinger() { return mFlinger.get(); }
     scheduler::TestableScheduler *scheduler() { return mScheduler; }
 
-    auto& mutableConfig() { return mConfig; }
-
     void initializeDisplays() {
         FTL_FAKE_GUARD(kMainThreadContext, mFlinger->initializeDisplays());
     }
@@ -700,6 +695,10 @@
         mFactory.mCreateNativeWindowSurface = f;
     }
 
+    void setInternalDisplayPrimaries(const ui::DisplayPrimaries &primaries) {
+        memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries));
+    }
+
     static auto &mutableLayerDrawingState(const sp<Layer> &layer) { return layer->mDrawingState; }
 
     auto &mutableStateLock() { return mFlinger->mStateLock; }
@@ -765,12 +764,13 @@
 
     auto calculateMaxAcquiredBufferCount(Fps refreshRate,
                                          std::chrono::nanoseconds presentLatency) const {
-        return mFlinger->calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
+        return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
     }
 
     /* Read-write access to private data to set up preconditions and assert
      * post-conditions.
      */
+    auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; }
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
     auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableDrawingState() { return mFlinger->mDrawingState; }
@@ -794,8 +794,8 @@
     void triggerOnFrameRateOverridesChanged() override {}
 
     surfaceflinger::test::Factory mFactory;
-    surfaceflinger::Config mConfig = surfaceflinger::Config::makeDefault(&mFactory);
-    sp<SurfaceFlinger> mFlinger = sp<SurfaceFlinger>::make(mConfig);
+    sp<SurfaceFlinger> mFlinger =
+            sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
     scheduler::TestableScheduler *mScheduler = nullptr;
     std::shared_ptr<scheduler::RefreshRateSelector> mRefreshRateSelector;
 };
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp
index c16a005..849a896 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_service_fuzzer.cpp
@@ -17,15 +17,13 @@
 #include <fuzzbinder/libbinder_driver.h>
 
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerConfig.h"
 #include "SurfaceFlingerDefaultFactory.h"
 
 using namespace android;
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     DefaultFactory factory;
-    surfaceflinger::Config config = surfaceflinger::Config::makeDefault(&factory);
-    sp<SurfaceFlinger> flinger = sp<SurfaceFlinger>::make(config);
+    sp<SurfaceFlinger> flinger = sp<SurfaceFlinger>::make(factory);
     flinger->init();
 
     sp<SurfaceComposerAIDL> composerAIDL = sp<SurfaceComposerAIDL>::make(flinger);
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 7124f87..e32cf88 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -34,7 +34,7 @@
             ::testing::UnitTest::GetInstance()->current_test_info();
     ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
 
-    mFlinger.mutableConfig().supportsWideColor = false;
+    mFlinger.mutableSupportsWideColor() = false;
     mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
 
     mFlinger.setCreateBufferQueueFunction([](auto, auto, auto) {
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index 5599a7a..ee12276 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -684,7 +684,7 @@
     static constexpr bool WIDE_COLOR_SUPPORTED = false;
 
     static void injectConfigChange(DisplayTransactionTest* test) {
-        test->mFlinger.mutableConfig().supportsWideColor = true;
+        test->mFlinger.mutableSupportsWideColor() = true;
     }
 
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
@@ -699,7 +699,7 @@
     static constexpr bool WIDE_COLOR_SUPPORTED = false;
 
     static void injectConfigChange(DisplayTransactionTest* test) {
-        test->mFlinger.mutableConfig().supportsWideColor = false;
+        test->mFlinger.mutableSupportsWideColor() = false;
         test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
     }
 
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index 6c14f6e..fab3c0e 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -250,8 +250,10 @@
 
     EXPECT_EQ(1, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
 
-    mFlinger.mutableConfig().minAcquiredBuffers = 2;
+    const auto savedMinAcquiredBuffers = mFlinger.mutableMinAcquiredBuffers();
+    mFlinger.mutableMinAcquiredBuffers() = 2;
     EXPECT_EQ(2, mFlinger.calculateMaxAcquiredBufferCount(60_Hz, 10ms));
+    mFlinger.mutableMinAcquiredBuffers() = savedMinAcquiredBuffers;
 }
 
 MATCHER(Is120Hz, "") {
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
index fe38384..5951c98 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_GetDisplayNativePrimariesTest.cpp
@@ -84,7 +84,9 @@
     injector.inject();
     auto internalDisplayToken = injector.token();
 
-    populateDummyDisplayNativePrimaries(mFlinger.mutableConfig().internalDisplayPrimaries);
+    ui::DisplayPrimaries expectedPrimaries;
+    populateDummyDisplayNativePrimaries(expectedPrimaries);
+    mFlinger.setInternalDisplayPrimaries(expectedPrimaries);
 
     ui::DisplayPrimaries primaries;
     EXPECT_EQ(NO_ERROR, mFlinger.getDisplayNativePrimaries(internalDisplayToken, primaries));
diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
index 61891c1..c0796df 100644
--- a/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_SetupNewDisplayDeviceInternalTest.cpp
@@ -36,7 +36,7 @@
     static constexpr bool WIDE_COLOR_SUPPORTED = true;
 
     static void injectConfigChange(DisplayTransactionTest* test) {
-        test->mFlinger.mutableConfig().supportsWideColor = true;
+        test->mFlinger.mutableSupportsWideColor() = true;
         test->mFlinger.mutableDisplayColorSetting() = DisplayColorSetting::kUnmanaged;
     }
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 099abf5..156c40a 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -45,8 +45,6 @@
 #include "Scheduler/RefreshRateSelector.h"
 #include "StartPropertySetThread.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerConfig.h"
-#include "SurfaceFlingerDefaultFactory.h"
 #include "TestableScheduler.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/DisplayHardware/MockDisplayMode.h"
@@ -170,15 +168,13 @@
 
     TestableSurfaceFlinger(sp<SurfaceFlinger> flinger = nullptr) : mFlinger(flinger) {
         if (!mFlinger) {
-            mFlinger = sp<SurfaceFlinger>::make(mConfig);
+            mFlinger = sp<SurfaceFlinger>::make(mFactory, SurfaceFlinger::SkipInitialization);
         }
     }
 
     SurfaceFlinger* flinger() { return mFlinger.get(); }
     scheduler::TestableScheduler* scheduler() { return mScheduler; }
 
-    auto& mutableConfig() { return mConfig; }
-
     // Extend this as needed for accessing SurfaceFlinger private (and public)
     // functions.
 
@@ -316,6 +312,10 @@
         mFactory.mCreateNativeWindowSurface = f;
     }
 
+    void setInternalDisplayPrimaries(const ui::DisplayPrimaries& primaries) {
+        memcpy(&mFlinger->mInternalDisplayPrimaries, &primaries, sizeof(ui::DisplayPrimaries));
+    }
+
     static auto& mutableLayerDrawingState(const sp<Layer>& layer) { return layer->mDrawingState; }
 
     auto& mutableStateLock() { return mFlinger->mStateLock; }
@@ -513,7 +513,7 @@
 
     auto calculateMaxAcquiredBufferCount(Fps refreshRate,
                                          std::chrono::nanoseconds presentLatency) const {
-        return mFlinger->calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
+        return SurfaceFlinger::calculateMaxAcquiredBufferCount(refreshRate, presentLatency);
     }
 
     auto setDesiredDisplayModeSpecs(const sp<IBinder>& displayToken,
@@ -596,6 +596,8 @@
     const auto& hwcPhysicalDisplayIdMap() const { return getHwComposer().mPhysicalDisplayIdMap; }
     const auto& hwcDisplayData() const { return getHwComposer().mDisplayData; }
 
+    auto& mutableSupportsWideColor() { return mFlinger->mSupportsWideColor; }
+
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
     auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
     auto& mutableDisplays() { return mFlinger->mDisplays; }
@@ -620,6 +622,8 @@
         return SurfaceFlinger::sActiveDisplayRotationFlags;
     }
 
+    auto& mutableMinAcquiredBuffers() { return SurfaceFlinger::minAcquiredBuffers; }
+
     auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }
 
     ~TestableSurfaceFlinger() {
@@ -1004,7 +1008,6 @@
     static constexpr VsyncId kVsyncId{123};
 
     surfaceflinger::test::Factory mFactory;
-    surfaceflinger::Config mConfig = surfaceflinger::Config::makeDefault(&mFactory);
     sp<SurfaceFlinger> mFlinger;
     scheduler::mock::SchedulerCallback mSchedulerCallback;
     scheduler::mock::NoOpSchedulerCallback mNoOpSchedulerCallback;