Merge "Add face authentication feature."
diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
index b32c92e..67abc68 100644
--- a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
+++ b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_IARC_VIDEO_BRIDGE_H
 #define ANDROID_IARC_VIDEO_BRIDGE_H
 
-#include <arc/IArcBridgeService.h>
+#include <arc/MojoBootstrapResult.h>
 #include <binder/IInterface.h>
 #include <utils/Errors.h>
 
diff --git a/include/android/choreographer.h b/include/android/choreographer.h
index 43346fe..11f8f6b 100644
--- a/include/android/choreographer.h
+++ b/include/android/choreographer.h
@@ -30,8 +30,6 @@
 
 __BEGIN_DECLS
 
-#if __ANDROID_API__ >= 24
-
 struct AChoreographer;
 typedef struct AChoreographer AChoreographer;
 
@@ -49,23 +47,23 @@
  * Get the AChoreographer instance for the current thread. This must be called
  * on an ALooper thread.
  */
-AChoreographer* AChoreographer_getInstance();
+AChoreographer* AChoreographer_getInstance() __INTRODUCED_IN(24);
 
 /**
  * Post a callback to be run on the next frame. The data pointer provided will
  * be passed to the callback function when it's called.
  */
 void AChoreographer_postFrameCallback(AChoreographer* choreographer,
-                AChoreographer_frameCallback callback, void* data);
+                AChoreographer_frameCallback callback, void* data) __INTRODUCED_IN(24);
+
 /**
  * Post a callback to be run on the frame following the specified delay. The
  * data pointer provided will be passed to the callback function when it's
  * called.
  */
 void AChoreographer_postFrameCallbackDelayed(AChoreographer* choreographer,
-                AChoreographer_frameCallback callback, void* data, long delayMillis);
-
-#endif /* __ANDROID_API__ >= 24 */
+                AChoreographer_frameCallback callback, void* data,
+                long delayMillis) __INTRODUCED_IN(24);
 
 __END_DECLS
 
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 6287332..81aedca 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -30,6 +30,10 @@
 
 #include <android/asset_manager.h>
 
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -671,53 +675,49 @@
  */
 void AConfiguration_setUiModeNight(AConfiguration* config, int32_t uiModeNight);
 
-#if __ANDROID_API__ >= 13
 /**
  * Return the current configuration screen width in dp units, or
  * ACONFIGURATION_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenWidthDp(AConfiguration* config);
+int32_t AConfiguration_getScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value);
+void AConfiguration_setScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
 
 /**
  * Return the current configuration screen height in dp units, or
  * ACONFIGURATION_SCREEN_HEIGHT_DP_ANY if not set.
  */
-int32_t AConfiguration_getScreenHeightDp(AConfiguration* config);
+int32_t AConfiguration_getScreenHeightDp(AConfiguration* config) __INTRODUCED_IN(13);
 
 /**
  * Set the configuration's current screen width in dp units.
  */
-void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value);
+void AConfiguration_setScreenHeightDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
 
 /**
  * Return the configuration's smallest screen width in dp units, or
  * ACONFIGURATION_SMALLEST_SCREEN_WIDTH_DP_ANY if not set.
  */
-int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config);
+int32_t AConfiguration_getSmallestScreenWidthDp(AConfiguration* config) __INTRODUCED_IN(13);
 
 /**
  * Set the configuration's smallest screen width in dp units.
  */
-void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value);
-#endif /* __ANDROID_API__ >= 13 */
+void AConfiguration_setSmallestScreenWidthDp(AConfiguration* config, int32_t value) __INTRODUCED_IN(13);
 
-#if __ANDROID_API__ >= 17
 /**
  * Return the configuration's layout direction, or
  * ACONFIGURATION_LAYOUTDIR_ANY if not set.
  */
-int32_t AConfiguration_getLayoutDirection(AConfiguration* config);
+int32_t AConfiguration_getLayoutDirection(AConfiguration* config) __INTRODUCED_IN(17);
 
 /**
  * Set the configuration's layout direction.
  */
-void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value);
-#endif /* __ANDROID_API__ >= 17 */
+void AConfiguration_setLayoutDirection(AConfiguration* config, int32_t value) __INTRODUCED_IN(17);
 
 /**
  * Perform a diff between two configurations.  Returns a bit mask of
diff --git a/include/android/input.h b/include/android/input.h
index f3f5312..3b36d2e 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -56,6 +56,10 @@
 #include <android/keycodes.h>
 #include <android/looper.h>
 
+#if !defined(__INTRODUCED_IN)
+#define __INTRODUCED_IN(__api_level) /* nothing */
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -982,10 +986,8 @@
  */
 int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event);
 
-#if __ANDROID_API__ >= 14
 /** Get the button state of all buttons that are pressed. */
-int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event);
-#endif
+int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event) __INTRODUCED_IN(14);
 
 /**
  * Get a bitfield indicating which edges, if any, were touched by this motion event.
@@ -1050,14 +1052,12 @@
  */
 int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index);
 
-#if __ANDROID_API__ >= 14
 /**
  * Get the tool type of a pointer for the given pointer index.
  * The tool type indicates the type of tool used to make contact such as a
  * finger or stylus, if known.
  */
-int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index);
-#endif
+int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index) __INTRODUCED_IN(14);
 
 /**
  * Get the original raw X coordinate of this event.
@@ -1147,11 +1147,9 @@
  */
 float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index);
 
-#if __ANDROID_API__ >= 13
 /** Get the value of the request axis for the given pointer index. */
 float AMotionEvent_getAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index);
-#endif
+        int32_t axis, size_t pointer_index) __INTRODUCED_IN(13);
 
 /**
  * Get the number of historical points in this event.  These are movements that
@@ -1282,14 +1280,12 @@
 float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index,
         size_t history_index);
 
-#if __ANDROID_API__ >= 13
 /**
  * Get the historical value of the request axis for the given pointer index
  * that occurred between this event and the previous motion event.
  */
 float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event,
-        int32_t axis, size_t pointer_index, size_t history_index);
-#endif
+        int32_t axis, size_t pointer_index, size_t history_index) __INTRODUCED_IN(13);
 
 
 struct AInputQueue;
diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h
index 5f2a57f..55df9f8 100644
--- a/include/android/multinetwork.h
+++ b/include/android/multinetwork.h
@@ -60,8 +60,6 @@
  * on failure with an appropriate errno value set.
  */
 
-#if __ANDROID_API__ >= 24
-
 /**
  * Set the network to be used by the given socket file descriptor.
  *
@@ -70,7 +68,7 @@
  * This is the equivalent of: [android.net.Network#bindSocket()](https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket))
  *
  */
-int android_setsocknetwork(net_handle_t network, int fd);
+int android_setsocknetwork(net_handle_t network, int fd) __INTRODUCED_IN(23);
 
 
 /**
@@ -87,7 +85,7 @@
  * This is the equivalent of: [android.net.ConnectivityManager#setProcessDefaultNetwork()](https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network))
  *
  */
-int android_setprocnetwork(net_handle_t network);
+int android_setprocnetwork(net_handle_t network) __INTRODUCED_IN(23);
 
 
 /**
@@ -106,9 +104,7 @@
  */
 int android_getaddrinfofornetwork(net_handle_t network,
         const char *node, const char *service,
-        const struct addrinfo *hints, struct addrinfo **res);
-
-#endif /* __ANDROID_API__ >= 24 */
+        const struct addrinfo *hints, struct addrinfo **res) __INTRODUCED_IN(23);
 
 __END_DECLS
 
diff --git a/include/android/native_window_jni.h b/include/android/native_window_jni.h
index 082fab2..74e43c7 100644
--- a/include/android/native_window_jni.h
+++ b/include/android/native_window_jni.h
@@ -44,7 +44,6 @@
  */
 ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
 
-#if __ANDROID_API__ >= 26
 /**
  * Return a Java Surface object derived from the ANativeWindow, for interacting
  * with it through Java code. The returned Java object acquires a reference on
@@ -52,8 +51,7 @@
  * and will automatically release the reference when the Java object gets garbage
  * collected.
  */
-jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window);
-#endif
+jobject ANativeWindow_toSurface(JNIEnv* env, ANativeWindow* window) __INTRODUCED_IN(26);
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 191777c..59229c1 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -478,7 +478,6 @@
 ASensorManager* ASensorManager_getInstance();
 #endif
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
 /**
  * Get a reference to the sensor manager. ASensorManager is a singleton
  * per package as different packages may have access to different sensors.
@@ -488,8 +487,7 @@
  *     ASensorManager* sensorManager = ASensorManager_getInstanceForPackage("foo.bar.baz");
  *
  */
-ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName);
-#endif
+ASensorManager* ASensorManager_getInstanceForPackage(const char* packageName) __INTRODUCED_IN(26);
 
 /**
  * Returns the list of available sensors.
@@ -502,13 +500,11 @@
  */
 ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
 
-#if __ANDROID_API__ >= 21
 /**
  * Returns the default sensor with the given type and wakeUp properties or NULL if no sensor
  * of this type and wakeUp properties exists.
  */
-ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp);
-#endif
+ASensor const* ASensorManager_getDefaultSensorEx(ASensorManager* manager, int type, bool wakeUp) __INTRODUCED_IN(21);
 
 /**
  * Creates a new sensor event queue and associate it with a looper.
@@ -525,7 +521,6 @@
  */
 int ASensorManager_destroyEventQueue(ASensorManager* manager, ASensorEventQueue* queue);
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
 /**
  * Create direct channel based on shared memory
  *
@@ -542,7 +537,7 @@
  *         {@link ASensorManager_destroyDirectChannel} and
  *         {@link ASensorManager_configureDirectReport}, or value less or equal to 0 for failures.
  */
-int ASensorManager_createSharedMemoryDirectChannel(ASensorManager* manager, int fd, size_t size);
+int ASensorManager_createSharedMemoryDirectChannel(ASensorManager* manager, int fd, size_t size) __INTRODUCED_IN(26);
 
 /**
  * Create direct channel based on AHardwareBuffer
@@ -560,7 +555,7 @@
  *         {@link ASensorManager_configureDirectReport}, or value less or equal to 0 for failures.
  */
 int ASensorManager_createHardwareBufferDirectChannel(
-        ASensorManager* manager, AHardwareBuffer const * buffer, size_t size);
+        ASensorManager* manager, AHardwareBuffer const * buffer, size_t size) __INTRODUCED_IN(26);
 
 /**
  * Destroy a direct channel
@@ -575,7 +570,7 @@
  *                  {@link ASensorManager_createSharedMemoryDirectChannel} or
  *                  {@link ASensorManager_createHardwareBufferDirectChannel}.
  */
-void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId);
+void ASensorManager_destroyDirectChannel(ASensorManager* manager, int channelId) __INTRODUCED_IN(26);
 
 /**
  * Configure direct report on channel
@@ -612,9 +607,8 @@
  *
  * \return positive token for success or negative error code.
  */
-int ASensorManager_configureDirectReport(
-        ASensorManager* manager, ASensor const* sensor, int channelId, int rate);
-#endif
+int ASensorManager_configureDirectReport(ASensorManager* manager,
+        ASensor const* sensor, int channelId, int rate) __INTRODUCED_IN(26);
 
 /*****************************************************************************/
 
@@ -733,35 +727,32 @@
  */
 int ASensor_getMinDelay(ASensor const* sensor);
 
-#if __ANDROID_API__ >= 21
 /**
  * Returns the maximum size of batches for this sensor. Batches will often be
  * smaller, as the hardware fifo might be used for other sensors.
  */
-int ASensor_getFifoMaxEventCount(ASensor const* sensor);
+int ASensor_getFifoMaxEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the hardware batch fifo size reserved to this sensor.
  */
-int ASensor_getFifoReservedEventCount(ASensor const* sensor);
+int ASensor_getFifoReservedEventCount(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns this sensor's string type.
  */
-const char* ASensor_getStringType(ASensor const* sensor);
+const char* ASensor_getStringType(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns the reporting mode for this sensor. One of AREPORTING_MODE_* constants.
  */
-int ASensor_getReportingMode(ASensor const* sensor);
+int ASensor_getReportingMode(ASensor const* sensor) __INTRODUCED_IN(21);
 
 /**
  * Returns true if this is a wake up sensor, false otherwise.
  */
-bool ASensor_isWakeUpSensor(ASensor const* sensor);
-#endif /* __ANDROID_API__ >= 21 */
+bool ASensor_isWakeUpSensor(ASensor const* sensor) __INTRODUCED_IN(21);
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
 /**
  * Test if sensor supports a certain type of direct channel.
  *
@@ -771,7 +762,8 @@
  *                     or {@link ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER}.
  * \returns true if sensor supports the specified direct channel type.
  */
-bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType);
+bool ASensor_isDirectChannelTypeSupported(ASensor const* sensor, int channelType) __INTRODUCED_IN(26);
+
 /**
  * Get the highest direct rate level that a sensor support.
  *
@@ -781,8 +773,7 @@
  *         If return value is {@link ASENSOR_DIRECT_RATE_STOP}, it means the sensor
  *         does not support direct report.
  */
-int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor);
-#endif
+int ASensor_getHighestDirectReportRateLevel(ASensor const* sensor) __INTRODUCED_IN(26);
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index 46d2f4b..0354f17 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -52,8 +52,6 @@
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= __ANDROID_API_O__
-
 /**
  * Create a shared memory region.
  *
@@ -67,7 +65,7 @@
  * \param size size of the shared memory region
  * \return file descriptor that denotes the shared memory; error code on failure.
  */
-int ASharedMemory_create(const char *name, size_t size);
+int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26);
 
 /**
  * Get the size of the shared memory region.
@@ -75,7 +73,7 @@
  * \param fd file descriptor of the shared memory region
  * \return size in bytes; 0 if fd is not a valid shared memory file descriptor.
  */
-size_t ASharedMemory_getSize(int fd);
+size_t ASharedMemory_getSize(int fd) __INTRODUCED_IN(26);
 
 /**
  * Restrict access of shared memory region.
@@ -106,9 +104,7 @@
  *             updated access. Note access can only be removed, but not added back.
  * \return 0 for success, error code on failure.
  */
-int ASharedMemory_setProt(int fd, int prot);
-
-#endif
+int ASharedMemory_setProt(int fd, int prot) __INTRODUCED_IN(26);
 
 #ifdef __cplusplus
 };
diff --git a/include/android/sharedmem_jni.h b/include/android/sharedmem_jni.h
index 85ac78f..d8b514f 100644
--- a/include/android/sharedmem_jni.h
+++ b/include/android/sharedmem_jni.h
@@ -54,8 +54,6 @@
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= __ANDROID_API_O_MR1__
-
 /**
  * Returns a dup'd FD from the given Java android.os.SharedMemory object. The returned file
  * descriptor has all the same properties & capabilities as the FD returned from
@@ -70,9 +68,7 @@
  *      already closed, if the JNIEnv or jobject is NULL, or if there are too many open file
  *      descriptors (errno=EMFILE)
  */
-int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory);
-
-#endif
+int ASharedMemory_dupFromJava(JNIEnv* env, jobject sharedMemory) __INTRODUCED_IN(27);
 
 #ifdef __cplusplus
 };
diff --git a/include/android/surface_texture.h b/include/android/surface_texture.h
index 56b3342..db10a16 100644
--- a/include/android/surface_texture.h
+++ b/include/android/surface_texture.h
@@ -64,7 +64,7 @@
  * Failing to do so will result in leaked memory and graphic resources.
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
-void ASurfaceTexture_release(ASurfaceTexture* st);
+void ASurfaceTexture_release(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Returns a reference to an ANativeWindow (i.e. the Producer) for this SurfaceTexture.
@@ -75,7 +75,7 @@
  * using ANativeWindow_release(). Failing to do so will result in leaked resources. nullptr is
  * returned if \st is null or if it's not an instance of android.graphics.SurfaceTexture
  */
-ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st);
+ANativeWindow* ASurfaceTexture_acquireANativeWindow(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Attach the SurfaceTexture to the OpenGL ES context that is current on the calling thread.  A
@@ -92,7 +92,7 @@
  * must be unusued in the OpenGL ES context that is current on the calling thread.
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
-int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName);
+int ASurfaceTexture_attachToGLContext(ASurfaceTexture* st, uint32_t texName) __INTRODUCED_IN(28);
 
 /**
  * Detach the SurfaceTexture from the OpenGL ES context that owns the OpenGL ES texture object.
@@ -108,7 +108,7 @@
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
-int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st);
+int ASurfaceTexture_detachFromGLContext(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Update the texture image to the most recent frame from the image stream.  This may only be
@@ -118,7 +118,7 @@
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  * \return 0 on success, negative posix error code otherwise (see <errno.h>)
  */
-int ASurfaceTexture_updateTexImage(ASurfaceTexture* st);
+int ASurfaceTexture_updateTexImage(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 /**
  * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by
@@ -136,7 +136,7 @@
  * \param mtx the array into which the 4x4 matrix will be stored.  The array must have exactly
  *     16 elements.
  */
-void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]);
+void ASurfaceTexture_getTransformMatrix(ASurfaceTexture* st, float mtx[16]) __INTRODUCED_IN(28);
 
 /**
  * Retrieve the timestamp associated with the texture image set by the most recent call to
@@ -155,7 +155,7 @@
  *
  * \param st A ASurfaceTexture reference acquired with ASurfaceTexture_fromSurfaceTexture()
  */
-int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st);
+int64_t ASurfaceTexture_getTimestamp(ASurfaceTexture* st) __INTRODUCED_IN(28);
 
 __END_DECLS
 
diff --git a/include/android/trace.h b/include/android/trace.h
index d9e5d88..9f59acf 100644
--- a/include/android/trace.h
+++ b/include/android/trace.h
@@ -37,13 +37,11 @@
 extern "C" {
 #endif
 
-#if __ANDROID_API__ >= 23
-
 /**
  * Returns true if tracing is enabled. Use this signal to avoid expensive computation only necessary
  * when tracing is enabled.
  */
-bool ATrace_isEnabled();
+bool ATrace_isEnabled() __INTRODUCED_IN(23);
 
 /**
  * Writes a tracing message to indicate that the given section of code has begun. This call must be
@@ -53,7 +51,7 @@
  * by the tracing mechanism. If sectionName contains these characters they will be replaced with a
  * space character in the trace.
  */
-void ATrace_beginSection(const char* sectionName);
+void ATrace_beginSection(const char* sectionName) __INTRODUCED_IN(23);
 
 /**
  * Writes a tracing message to indicate that a given section of code has ended. This call must be
@@ -61,9 +59,7 @@
  * will mark the end of the most recently begun section of code, so care must be taken to ensure
  * that beginSection / endSection pairs are properly nested and called from the same thread.
  */
-void ATrace_endSection();
-
-#endif /* __ANDROID_API__ >= 23 */
+void ATrace_endSection() __INTRODUCED_IN(23);
 
 #ifdef __cplusplus
 };
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 49ffc8f..7e26b0b 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -286,6 +286,35 @@
     return gbuffer->handle;
 }
 
+int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc,
+                                     const native_handle_t* handle, int32_t method,
+                                     AHardwareBuffer** outBuffer) {
+    static_assert(static_cast<int32_t>(AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER) ==
+                  static_cast<int32_t>(GraphicBuffer::TAKE_UNREGISTERED_HANDLE));
+    static_assert(static_cast<int32_t>(AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE) ==
+                  static_cast<int32_t>(GraphicBuffer::CLONE_HANDLE));
+
+    if (!desc || !handle || !outBuffer) return BAD_VALUE;
+    if (!(method == AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER ||
+          method == AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE))
+        return BAD_VALUE;
+    if (desc->rfu0 != 0 || desc->rfu1 != 0) return BAD_VALUE;
+    if (desc->format == AHARDWAREBUFFER_FORMAT_BLOB && desc->height != 1) return BAD_VALUE;
+
+    const int format = AHardwareBuffer_convertToPixelFormat(desc->format);
+    const uint64_t usage = AHardwareBuffer_convertToGrallocUsageBits(desc->usage);
+    const auto wrapMethod = static_cast<GraphicBuffer::HandleWrapMethod>(method);
+    sp<GraphicBuffer> gbuffer(new GraphicBuffer(handle, wrapMethod, desc->width, desc->height,
+                                                format, desc->layers, usage, desc->stride));
+    status_t err = gbuffer->initCheck();
+    if (err != 0 || gbuffer->handle == 0) return err;
+
+    *outBuffer = AHardwareBuffer_from_GraphicBuffer(gbuffer.get());
+    // Ensure the buffer doesn't get destroyed when the sp<> goes away.
+    AHardwareBuffer_acquire(*outBuffer);
+
+    return NO_ERROR;
+}
 
 // ----------------------------------------------------------------------------
 // Helpers implementation
diff --git a/libs/nativewindow/include/android/hardware_buffer.h b/libs/nativewindow/include/android/hardware_buffer.h
index 32b9266..080387b 100644
--- a/libs/nativewindow/include/android/hardware_buffer.h
+++ b/libs/nativewindow/include/android/hardware_buffer.h
@@ -223,25 +223,25 @@
  * any reason. The returned buffer has a reference count of 1.
  */
 int AHardwareBuffer_allocate(const AHardwareBuffer_Desc* desc,
-        AHardwareBuffer** outBuffer);
+        AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
 /**
  * Acquire a reference on the given AHardwareBuffer object.  This prevents the
  * object from being deleted until the last reference is removed.
  */
-void AHardwareBuffer_acquire(AHardwareBuffer* buffer);
+void AHardwareBuffer_acquire(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Remove a reference that was previously acquired with
  * AHardwareBuffer_acquire().
  */
-void AHardwareBuffer_release(AHardwareBuffer* buffer);
+void AHardwareBuffer_release(AHardwareBuffer* buffer) __INTRODUCED_IN(26);
 
 /**
  * Return a description of the AHardwareBuffer in the passed
  * AHardwareBuffer_Desc struct.
  */
 void AHardwareBuffer_describe(const AHardwareBuffer* buffer,
-        AHardwareBuffer_Desc* outDesc);
+        AHardwareBuffer_Desc* outDesc) __INTRODUCED_IN(26);
 
 /**
  * Lock the AHardwareBuffer for reading or writing, depending on the usage flags
@@ -277,7 +277,7 @@
  * number of the lock fails for any reason.
  */
 int AHardwareBuffer_lock(AHardwareBuffer* buffer, uint64_t usage,
-        int32_t fence, const ARect* rect, void** outVirtualAddress);
+        int32_t fence, const ARect* rect, void** outVirtualAddress) __INTRODUCED_IN(26);
 
 /**
  * Unlock the AHardwareBuffer; must be called after all changes to the buffer
@@ -289,7 +289,7 @@
  * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
  * number if the unlock fails for any reason.
  */
-int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence);
+int AHardwareBuffer_unlock(AHardwareBuffer* buffer, int32_t* fence) __INTRODUCED_IN(26);
 
 /**
  * Send the AHardwareBuffer to an AF_UNIX socket.
@@ -297,7 +297,7 @@
  * \return 0 on success, -EINVAL if \a buffer is NULL, or an error
  * number if the operation fails for any reason.
  */
-int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd);
+int AHardwareBuffer_sendHandleToUnixSocket(const AHardwareBuffer* buffer, int socketFd) __INTRODUCED_IN(26);
 
 /**
  * Receive the AHardwareBuffer from an AF_UNIX socket.
@@ -305,7 +305,7 @@
  * \return 0 on success, -EINVAL if \a outBuffer is NULL, or an error
  * number if the operation fails for any reason.
  */
-int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer);
+int AHardwareBuffer_recvHandleFromUnixSocket(int socketFd, AHardwareBuffer** outBuffer) __INTRODUCED_IN(26);
 
 __END_DECLS
 
diff --git a/libs/nativewindow/include/android/native_window.h b/libs/nativewindow/include/android/native_window.h
index d5e5e9d..78d32e4 100644
--- a/libs/nativewindow/include/android/native_window.h
+++ b/libs/nativewindow/include/android/native_window.h
@@ -109,33 +109,33 @@
  * Acquire a reference on the given {@link ANativeWindow} object. This prevents the object
  * from being deleted until the reference is removed.
  */
-void ANativeWindow_acquire(ANativeWindow* window);
+void ANativeWindow_acquire(ANativeWindow* window) __INTRODUCED_IN(26);
 
 /**
  * Remove a reference that was previously acquired with {@link ANativeWindow_acquire()}.
  */
-void ANativeWindow_release(ANativeWindow* window);
+void ANativeWindow_release(ANativeWindow* window) __INTRODUCED_IN(26);
 
 /**
  * Return the current width in pixels of the window surface.
  *
  * \return negative value on error.
  */
-int32_t ANativeWindow_getWidth(ANativeWindow* window);
+int32_t ANativeWindow_getWidth(ANativeWindow* window) __INTRODUCED_IN(26);
 
 /**
  * Return the current height in pixels of the window surface.
  *
  * \return a negative value on error.
  */
-int32_t ANativeWindow_getHeight(ANativeWindow* window);
+int32_t ANativeWindow_getHeight(ANativeWindow* window) __INTRODUCED_IN(26);
 
 /**
  * Return the current pixel format (AHARDWAREBUFFER_FORMAT_*) of the window surface.
  *
  * \return a negative value on error.
  */
-int32_t ANativeWindow_getFormat(ANativeWindow* window);
+int32_t ANativeWindow_getFormat(ANativeWindow* window) __INTRODUCED_IN(26);
 
 /**
  * Change the format and size of the window buffers.
@@ -155,7 +155,7 @@
  * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window,
-        int32_t width, int32_t height, int32_t format);
+        int32_t width, int32_t height, int32_t format) __INTRODUCED_IN(26);
 
 /**
  * Lock the window's next drawing surface for writing.
@@ -168,7 +168,7 @@
  * \return 0 for success, or a negative value on error.
  */
 int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer,
-        ARect* inOutDirtyBounds);
+        ARect* inOutDirtyBounds) __INTRODUCED_IN(26);
 
 /**
  * Unlock the window's drawing surface after previously locking it,
@@ -176,9 +176,7 @@
  *
  * \return 0 for success, or a negative value on error.
  */
-int32_t ANativeWindow_unlockAndPost(ANativeWindow* window);
-
-#if __ANDROID_API__ >= __ANDROID_API_O__
+int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) __INTRODUCED_IN(26);
 
 /**
  * Set a transform that will be applied to future buffers posted to the window.
@@ -186,9 +184,7 @@
  * \param transform combination of {@link ANativeWindowTransform} flags
  * \return 0 for success, or -EINVAL if \p transform is invalid
  */
-int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform);
-
-#endif // __ANDROID_API__ >= __ANDROID_API_O__
+int32_t ANativeWindow_setBuffersTransform(ANativeWindow* window, int32_t transform) __INTRODUCED_IN(26);
 
 #if __ANDROID_API__ >= __ANDROID_API_P__
 
diff --git a/libs/nativewindow/include/vndk/hardware_buffer.h b/libs/nativewindow/include/vndk/hardware_buffer.h
index 7a4b31f..6c9ec34 100644
--- a/libs/nativewindow/include/vndk/hardware_buffer.h
+++ b/libs/nativewindow/include/vndk/hardware_buffer.h
@@ -26,6 +26,28 @@
 
 const native_handle_t* AHardwareBuffer_getNativeHandle(const AHardwareBuffer* buffer);
 
+enum CreateFromHandleMethod {
+    // enum values chosen to match internal GraphicBuffer::HandleWrapMethod
+    AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER = 2,
+    AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE = 3,
+};
+
+/**
+ * Create a AHardwareBuffer from a native handle.
+ *
+ * This function wraps a native handle in a AHardwareBuffer suitable for use by applications or
+ * other parts of the system. The contents of desc will be returned by AHardwareBuffer_describe().
+ *
+ * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_REGISTER, the handle is assumed to be
+ * unregistered, and it will be registered/imported before being wrapped in the AHardwareBuffer.
+ * If successful, the AHardwareBuffer will own the handle.
+ *
+ * If method is AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, the handle will be cloned and the
+ * clone registered. The AHardwareBuffer will own the cloned handle but not the original.
+ */
+int AHardwareBuffer_createFromHandle(const AHardwareBuffer_Desc* desc,
+                                     const native_handle_t* handle, int32_t method,
+                                     AHardwareBuffer** outBuffer);
 
 /**
  * Buffer pixel formats.
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index d2ba971..753954d 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -2,6 +2,7 @@
   global:
     AHardwareBuffer_acquire;
     AHardwareBuffer_allocate;
+    AHardwareBuffer_createFromHandle; # vndk
     AHardwareBuffer_describe;
     AHardwareBuffer_getNativeHandle; # vndk
     AHardwareBuffer_lock;
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index 8508c5f..297a8a3 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -55,13 +55,38 @@
 void egl_tls_t::validateTLSKey()
 {
     struct TlsKeyInitializer {
-        static void create() {
-            pthread_key_create(&sKey, (void (*)(void*))&eglReleaseThread);
-        }
+        static void create() { pthread_key_create(&sKey, destructTLSData); }
     };
     pthread_once(&sOnceKey, TlsKeyInitializer::create);
 }
 
+void egl_tls_t::destructTLSData(void* data) {
+    egl_tls_t* tls = static_cast<egl_tls_t*>(data);
+    if (!tls) return;
+
+    // Several things in the call tree of eglReleaseThread expect to be able to get the current
+    // thread state directly from TLS. That's a problem because Bionic has already cleared our
+    // TLS pointer before calling this function (pthread_getspecific(sKey) will return nullptr).
+    // Instead the data is passed as our parameter.
+    //
+    // Ideally we'd refactor this so we have thin wrappers that retrieve thread state from TLS and
+    // then pass it as a parameter (or 'this' pointer) to functions that do the real work without
+    // touching TLS. Then from here we could just call those implementation functions with the the
+    // TLS data we just received as a parameter.
+    //
+    // But that's a fairly invasive refactoring, so to do this robustly in the short term we just
+    // put the data *back* in TLS and call the top-level eglReleaseThread. It and it's call tree
+    // will retrieve the value from TLS, and then finally clear the TLS data. Bionic explicitly
+    // tolerates re-setting the value that it's currently trying to destruct (see
+    // pthread_key_clean_all()). Even if we forgot to clear the restored TLS data, bionic would
+    // call the destructor again, but eventually gives up and just leaks the data rather than
+    // enter an infinite loop.
+    pthread_setspecific(sKey, tls);
+    eglReleaseThread();
+    ALOGE_IF(pthread_getspecific(sKey) != nullptr,
+             "EGL TLS data still exists after eglReleaseThread");
+}
+
 void egl_tls_t::setErrorEtcImpl(
         const char* caller, int line, EGLint error, bool quiet) {
     validateTLSKey();
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index 9feae68..86a375c 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -38,6 +38,7 @@
 
     egl_tls_t();
     static void validateTLSKey();
+    static void destructTLSData(void* data);
     static void setErrorEtcImpl(
             const char* caller, int line, EGLint error, bool quiet);
 
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 133e8f7..aae3931 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -326,7 +326,7 @@
     if (presentFence->isValid()) {
         mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
         mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
-    } else {
+    } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
         const nsecs_t actualPresentTime =
@@ -613,6 +613,11 @@
     const auto& viewport = display->getViewport();
     Region visible = tr.transform(visibleRegion.intersect(viewport));
     const auto displayId = display->getId();
+    if (!hasHwcLayer(displayId)) {
+        ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+              mName.string(), displayId);
+        return;
+    }
     auto& hwcInfo = getBE().mHwcLayers[displayId];
     auto& hwcLayer = hwcInfo.layer;
     auto error = hwcLayer->setVisibleRegion(visible);
@@ -667,8 +672,7 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    getBE().mHwcLayers[displayId].bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer,
-                                                           &hwcSlot, &hwcBuffer);
+    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
@@ -706,8 +710,9 @@
         mProducer->setMaxDequeuedBufferCount(2);
     }
 
-    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
-    updateTransformHint(hw);
+    if (const auto display = mFlinger->getDefaultDisplayDevice()) {
+        updateTransformHint(display);
+    }
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index ab8afb6..aebe4ea 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -66,6 +66,11 @@
     const auto& viewport = display->getViewport();
     Region visible = tr.transform(visibleRegion.intersect(viewport));
     const auto displayId = display->getId();
+    if (!hasHwcLayer(displayId)) {
+        ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+              mName.string(), displayId);
+        return;
+    }
     auto& hwcInfo = getBE().mHwcLayers[displayId];
     auto& hwcLayer = hwcInfo.layer;
     auto error = hwcLayer->setVisibleRegion(visible);
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 7acbd11..37dc27d 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -222,7 +222,13 @@
                 // Pretend that the last time this event was handled at the same frame but with the
                 // new offset to allow for a seamless offset change without double-firing or
                 // skipping.
-                listener.mLastEventTime -= (oldPhase - phase);
+                nsecs_t diff = oldPhase - phase;
+                if (diff > mPeriod / 2) {
+                    diff -= mPeriod;
+                } else if (diff < -mPeriod / 2) {
+                    diff += mPeriod;
+                }
+                listener.mLastEventTime -= diff;
                 mCond.signal();
                 return NO_ERROR;
             }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index a4a6554..f440d29 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -315,7 +315,6 @@
 };
 
 struct DisplayDeviceState {
-    bool isValid() const { return type >= 0; }
     bool isVirtual() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
 
     int32_t sequenceId = sNextSequenceId++;
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index f626a59..9546c86 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -124,6 +124,12 @@
     return mComposer->getMaxVirtualDisplayCount();
 }
 
+Error Device::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+                                           std::vector<uint8_t>* outData) const {
+    auto intError = mComposer->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
+    return static_cast<Error>(intError);
+}
+
 Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
         PixelFormat* format, Display** outDisplay)
 {
@@ -460,11 +466,6 @@
     return configs;
 }
 
-Error Display::getIdentificationData(uint8_t* outPort, std::vector<uint8_t>* outData) const {
-    auto intError = mComposer.getDisplayIdentificationData(mId, outPort, outData);
-    return static_cast<Error>(intError);
-}
-
 Error Display::getName(std::string* outName) const
 {
     auto intError = mComposer.getDisplayName(mId, outName);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 2cb6aea..eefab98 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -93,6 +93,9 @@
     };
 
     uint32_t getMaxVirtualDisplayCount() const;
+    Error getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+                                       std::vector<uint8_t>* outData) const;
+
     Error createVirtualDisplay(uint32_t width, uint32_t height,
             android::ui::PixelFormat* format, Display** outDisplay);
     void destroyDisplay(hwc2_display_t displayId);
@@ -224,8 +227,6 @@
     // Doesn't call into the HWC2 device, so no errors are possible
     std::vector<std::shared_ptr<const Config>> getConfigs() const;
 
-    [[clang::warn_unused_result]] Error getIdentificationData(uint8_t* outPort,
-                                                              std::vector<uint8_t>* outData) const;
     [[clang::warn_unused_result]] Error getName(std::string* outName) const;
     [[clang::warn_unused_result]] Error getRequests(
             DisplayRequest* outDisplayRequests,
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index cd0635a..4e98b88 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -54,6 +54,9 @@
 #include "../Layer.h"           // needed only for debugging
 #include "../SurfaceFlinger.h"
 
+#define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \
+    ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
+
 #define LOG_DISPLAY_ERROR(displayId, msg) \
     ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
 
@@ -96,17 +99,11 @@
     mHwcDevice->registerCallback(callback, sequenceId);
 }
 
-bool HWComposer::getDisplayIdentificationData(hwc2_display_t displayId, uint8_t* outPort,
+bool HWComposer::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
                                               DisplayIdentificationData* outData) const {
-    HWC2::Display* display = mHwcDevice->getDisplayById(displayId);
-    if (!display) {
-        ALOGE("getDisplayIdentificationData: Attempted to access invalid display %" PRIu64,
-              displayId);
-        return false;
-    }
-    const auto error = display->getIdentificationData(outPort, outData);
+    const auto error = mHwcDevice->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
     if (error != HWC2::Error::None) {
-        ALOGE("getDisplayIdentificationData failed for display %" PRIu64, displayId);
+        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, to_string(error).c_str());
         return false;
     }
     return true;
@@ -147,65 +144,53 @@
     }
 }
 
-std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t displayId, int32_t displayType,
+std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
                                                HWC2::Connection connection) {
     if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
         ALOGE("Invalid display type of %d", displayType);
         return {};
     }
 
-    ALOGV("hotplug: %" PRIu64 ", %s %s", displayId,
-            displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
-            to_string(connection).c_str());
-    mHwcDevice->onHotplug(displayId, connection);
+    ALOGV("hotplug: %" PRIu64 ", %s %s", hwcDisplayId,
+          displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
+          to_string(connection).c_str());
+    mHwcDevice->onHotplug(hwcDisplayId, connection);
 
-    std::optional<DisplayId> stableId;
+    std::optional<DisplayId> displayId;
 
     uint8_t port;
     DisplayIdentificationData data;
-    if (getDisplayIdentificationData(displayId, &port, &data)) {
-        stableId = generateDisplayId(port, data);
-        ALOGE_IF(!stableId, "Failed to generate stable ID for display %" PRIu64, displayId);
+    if (getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
+        displayId = generateDisplayId(port, data);
+        ALOGE_IF(!displayId, "Failed to generate stable ID for display %" PRIu64, hwcDisplayId);
     }
 
     // Disconnect is handled through HWComposer::disconnectDisplay via
     // SurfaceFlinger's onHotplugReceived callback handling
     if (connection == HWC2::Connection::Connected) {
-        mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(displayId);
-        mHwcDisplaySlots[displayId] = displayType;
+        mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+        mHwcDisplaySlots[hwcDisplayId] = displayType;
     }
 
-    return stableId;
+    return displayId;
 }
 
-bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp,
-                         int32_t* outDisplay) {
-    auto display = mHwcDevice->getDisplayById(displayId);
-    if (!display) {
-        ALOGE("onVsync Failed to find display %" PRIu64, displayId);
-        return false;
-    }
-    auto displayType = HWC2::DisplayType::Invalid;
-    auto error = display->getType(&displayType);
-    if (error != HWC2::Error::None) {
-        ALOGE("onVsync: Failed to determine type of display %" PRIu64,
-                display->getId());
+bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
+    const auto it = mHwcDisplaySlots.find(hwcDisplayId);
+    if (it == mHwcDisplaySlots.end()) {
+        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
         return false;
     }
 
-    if (displayType == HWC2::DisplayType::Virtual) {
-        ALOGE("Virtual display %" PRIu64 " passed to vsync callback",
-                display->getId());
+    const int32_t displayId = it->second;
+    RETURN_IF_INVALID_DISPLAY(displayId, false);
+
+    const auto& displayData = mDisplayData[displayId];
+    if (displayData.isVirtual) {
+        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
         return false;
     }
 
-    if (mHwcDisplaySlots.count(display->getId()) == 0) {
-        ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback",
-                display->getId());
-        return false;
-    }
-
-    int32_t disp = mHwcDisplaySlots[display->getId()];
     {
         Mutex::Autolock _l(mLock);
 
@@ -213,22 +198,22 @@
         // with the same timestamp when turning the display off and on. This
         // is a bug in the HWC implementation, but filter the extra events
         // out here so they don't cause havoc downstream.
-        if (timestamp == mLastHwVSync[disp]) {
+        if (timestamp == mLastHwVSync[displayId]) {
             ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
                     timestamp);
             return false;
         }
 
-        mLastHwVSync[disp] = timestamp;
+        mLastHwVSync[displayId] = timestamp;
     }
 
-    if (outDisplay) {
-        *outDisplay = disp;
+    if (outDisplayId) {
+        *outDisplayId = displayId;
     }
 
     char tag[16];
-    snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
-    ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
+    snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
+    ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);
 
     return true;
 }
@@ -236,16 +221,15 @@
 status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
         ui::PixelFormat* format, int32_t *outId) {
     if (mRemainingHwcVirtualDisplays == 0) {
-        ALOGE("allocateVirtualDisplay: No remaining virtual displays");
+        ALOGE("%s: No remaining virtual displays", __FUNCTION__);
         return NO_MEMORY;
     }
 
     if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
         (width > SurfaceFlinger::maxVirtualDisplaySize ||
          height > SurfaceFlinger::maxVirtualDisplaySize)) {
-        ALOGE("createVirtualDisplay: Can't create a virtual display with"
-                      " a dimension > %" PRIu64 " (tried %u x %u)",
-              SurfaceFlinger::maxVirtualDisplaySize, width, height);
+        ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
+              height, SurfaceFlinger::maxVirtualDisplaySize);
         return INVALID_OPERATION;
     }
 
@@ -253,7 +237,7 @@
     auto error = mHwcDevice->createVirtualDisplay(width, height, format,
             &display);
     if (error != HWC2::Error::None) {
-        ALOGE("allocateVirtualDisplay: Failed to create HWC virtual display");
+        ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
         return NO_MEMORY;
     }
 
@@ -266,11 +250,13 @@
         displaySlot = mDisplayData.size();
         mDisplayData.resize(displaySlot + 1);
     } else {
-        ALOGE("allocateVirtualDisplay: Unable to allocate a display slot");
+        ALOGE("%s: Unable to allocate a display slot", __FUNCTION__);
         return NO_MEMORY;
     }
 
-    mDisplayData[displaySlot].hwcDisplay = display;
+    auto& displayData = mDisplayData[displaySlot];
+    displayData.hwcDisplay = display;
+    displayData.isVirtual = true;
 
     --mRemainingHwcVirtualDisplays;
     *outId = static_cast<int32_t>(displaySlot);
@@ -347,21 +333,19 @@
 }
 
 int HWComposer::getActiveConfigIndex(int32_t displayId) const {
-    if (!isValidDisplay(displayId)) {
-        ALOGV("getActiveConfigIndex: Attempted to access invalid display %d", displayId);
-        return -1;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, -1);
+
     int index;
     auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
     if (error == HWC2::Error::BadConfig) {
-        ALOGE("getActiveConfigIndex: No config active, returning -1");
+        LOG_DISPLAY_ERROR(displayId, "No active config");
         return -1;
-    } else if (error != HWC2::Error::None) {
-        ALOGE("getActiveConfigIndex failed for display %d: %s (%d)", displayId,
-              to_string(error).c_str(), static_cast<int32_t>(error));
-        return -1;
-    } else if (index < 0) {
-        ALOGE("getActiveConfigIndex returned an unknown config for display %d", displayId);
+    }
+
+    RETURN_IF_HWC_ERROR(error, displayId, -1);
+
+    if (index < 0) {
+        LOG_DISPLAY_ERROR(displayId, "Unknown config");
         return -1;
     }
 
@@ -393,19 +377,19 @@
 
 
 void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
-    if (displayId < 0 || displayId >= HWC_DISPLAY_VIRTUAL) {
-        ALOGD("setVsyncEnabled: Ignoring for virtual display %d", displayId);
+    RETURN_IF_INVALID_DISPLAY(displayId);
+    auto& displayData = mDisplayData[displayId];
+
+    if (displayData.isVirtual) {
+        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
         return;
     }
 
-    RETURN_IF_INVALID_DISPLAY(displayId);
-
     // NOTE: we use our own internal lock here because we have to call
     // into the HWC with the lock held, and we want to make sure
     // that even if HWC blocks (which it shouldn't), it won't
     // affect other threads.
     Mutex::Autolock _l(mVsyncLock);
-    auto& displayData = mDisplayData[displayId];
     if (enabled != displayData.vsyncEnabled) {
         ATRACE_CALL();
         auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
@@ -629,7 +613,8 @@
     ALOGV("setPowerMode(%d, %d)", displayId, intMode);
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
-    if (displayId >= VIRTUAL_DISPLAY_ID_BASE) {
+    const auto& displayData = mDisplayData[displayId];
+    if (displayData.isVirtual) {
         LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
         return INVALID_OPERATION;
     }
@@ -639,7 +624,7 @@
         setVsyncEnabled(displayId, HWC2::Vsync::Disable);
     }
 
-    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+    auto& hwcDisplay = displayData.hwcDisplay;
     switch (mode) {
         case HWC2::PowerMode::Off:
         case HWC2::PowerMode::On:
@@ -708,24 +693,20 @@
     return NO_ERROR;
 }
 
-void HWComposer::disconnectDisplay(int displayId) {
-    LOG_ALWAYS_FATAL_IF(displayId < 0);
+void HWComposer::disconnectDisplay(int32_t displayId) {
+    RETURN_IF_INVALID_DISPLAY(displayId);
     auto& displayData = mDisplayData[displayId];
 
-    auto displayType = HWC2::DisplayType::Invalid;
-    auto error = displayData.hwcDisplay->getType(&displayType);
-    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId);
-
     // If this was a virtual display, add its slot back for reuse by future
     // virtual displays
-    if (displayType == HWC2::DisplayType::Virtual) {
+    if (displayData.isVirtual) {
         mFreeDisplaySlots.insert(displayId);
         ++mRemainingHwcVirtualDisplays;
     }
 
     const auto hwcDisplayId = displayData.hwcDisplay->getId();
     mHwcDisplaySlots.erase(hwcDisplayId);
-    displayData.reset();
+    displayData = DisplayData();
 
     mHwcDevice->destroyDisplay(hwcDisplayId);
 }
@@ -733,18 +714,14 @@
 status_t HWComposer::setOutputBuffer(int32_t displayId,
         const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+    const auto& displayData = mDisplayData[displayId];
 
-    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
-    auto displayType = HWC2::DisplayType::Invalid;
-    auto error = hwcDisplay->getType(&displayType);
-    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId, NAME_NOT_FOUND);
-
-    if (displayType != HWC2::DisplayType::Virtual) {
+    if (!displayData.isVirtual) {
         LOG_DISPLAY_ERROR(displayId, "Invalid operation on physical display");
         return INVALID_OPERATION;
     }
 
-    error = hwcDisplay->setOutputBuffer(buffer, acquireFence);
+    auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence);
     RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return NO_ERROR;
 }
@@ -833,26 +810,4 @@
     return mDisplayData[displayId].hwcDisplay->getId();
 }
 
-// ---------------------------------------------------------------------------
-
-HWComposer::DisplayData::DisplayData()
-  : hasClientComposition(false),
-    hasDeviceComposition(false),
-    hwcDisplay(nullptr),
-    lastPresentFence(Fence::NO_FENCE),
-    outbufHandle(nullptr),
-    outbufAcquireFence(Fence::NO_FENCE),
-    vsyncEnabled(HWC2::Vsync::Disable) {
-    ALOGV("Created new DisplayData");
-}
-
-HWComposer::DisplayData::~DisplayData() {
-}
-
-void HWComposer::DisplayData::reset() {
-    ALOGV("DisplayData reset");
-    *this = DisplayData();
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 9e4a683..3c5efea 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -76,7 +76,7 @@
     void registerCallback(HWC2::ComposerCallback* callback,
                           int32_t sequenceId);
 
-    bool getDisplayIdentificationData(hwc2_display_t displayId, uint8_t* outPort,
+    bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
                                       DisplayIdentificationData* outData) const;
 
     bool hasCapability(HWC2::Capability capability) const;
@@ -152,9 +152,8 @@
 
     // Returns true if successful, false otherwise. The
     // DisplayDevice::DisplayType of the display is returned as an output param.
-    bool onVsync(hwc2_display_t displayId, int64_t timestamp,
-                 int32_t* outDisplay);
-    std::optional<DisplayId> onHotplug(hwc2_display_t displayId, int32_t displayType,
+    bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay);
+    std::optional<DisplayId> onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
                                        HWC2::Connection connection);
 
     void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
@@ -189,31 +188,26 @@
     // For unit tests
     friend TestableSurfaceFlinger;
 
-    static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
-
     bool isValidDisplay(int32_t displayId) const;
     static void validateChange(HWC2::Composition from, HWC2::Composition to);
 
     struct cb_context;
 
     struct DisplayData {
-        DisplayData();
-        ~DisplayData();
-        void reset();
-
-        bool hasClientComposition;
-        bool hasDeviceComposition;
-        HWC2::Display* hwcDisplay;
+        bool isVirtual = false;
+        bool hasClientComposition = false;
+        bool hasDeviceComposition = false;
+        HWC2::Display* hwcDisplay = nullptr;
         HWC2::DisplayRequest displayRequests;
-        sp<Fence> lastPresentFence;  // signals when the last set op retires
+        sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
-        buffer_handle_t outbufHandle;
-        sp<Fence> outbufAcquireFence;
+        buffer_handle_t outbufHandle = nullptr;
+        sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
         mutable std::unordered_map<int32_t,
                 std::shared_ptr<const HWC2::Display::Config>> configMap;
 
         // protected by mVsyncLock
-        HWC2::Vsync vsyncEnabled;
+        HWC2::Vsync vsyncEnabled = HWC2::Vsync::Disable;
 
         bool validateWasSkipped;
         HWC2::Error presentError;
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index bc271c8..5a8fd25 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -155,20 +155,17 @@
     mCondition.notify_all();
 }
 
-void EventThread::onHotplugReceived(int type, bool connected) {
-    ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
-             "received hotplug event for an invalid display (id=%d)", type);
-
+void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
     std::lock_guard<std::mutex> lock(mMutex);
-    if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        DisplayEventReceiver::Event event;
-        event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
-        event.header.id = type;
-        event.header.timestamp = systemTime();
-        event.hotplug.connected = connected;
-        mPendingEvents.add(event);
-        mCondition.notify_all();
-    }
+
+    DisplayEventReceiver::Event event;
+    event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
+    event.header.id = displayType == DisplayType::Primary ? 0 : 1;
+    event.header.timestamp = systemTime();
+    event.hotplug.connected = connected;
+
+    mPendingEvents.add(event);
+    mCondition.notify_all();
 }
 
 void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
@@ -205,7 +202,7 @@
 // This will return when (1) a vsync event has been received, and (2) there was
 // at least one connection interested in receiving it when we started waiting.
 Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
-        std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {
+        std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* outEvent) {
     Vector<sp<EventThread::Connection> > signalConnections;
 
     while (signalConnections.isEmpty() && mKeepRunning) {
@@ -214,16 +211,16 @@
 
         size_t vsyncCount = 0;
         nsecs_t timestamp = 0;
-        for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {
-            timestamp = mVSyncEvent[i].header.timestamp;
+        for (auto& event : mVSyncEvent) {
+            timestamp = event.header.timestamp;
             if (timestamp) {
                 // we have a vsync event to dispatch
                 if (mInterceptVSyncsCallback) {
                     mInterceptVSyncsCallback(timestamp);
                 }
-                *event = mVSyncEvent[i];
-                mVSyncEvent[i].header.timestamp = 0;
-                vsyncCount = mVSyncEvent[i].vsync.count;
+                *outEvent = event;
+                event.header.timestamp = 0;
+                vsyncCount = event.vsync.count;
                 break;
             }
         }
@@ -233,7 +230,7 @@
             eventPending = !mPendingEvents.isEmpty();
             if (eventPending) {
                 // we have some other event to dispatch
-                *event = mPendingEvents[0];
+                *outEvent = mPendingEvents[0];
                 mPendingEvents.removeAt(0);
             }
         }
@@ -319,7 +316,7 @@
                     // FIXME: how do we decide which display id the fake
                     // vsync came from ?
                     mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-                    mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
+                    mVSyncEvent[0].header.id = 0;
                     mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                     mVSyncEvent[0].vsync.count++;
                 }
@@ -364,8 +361,7 @@
     result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
     result.appendFormat("  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
     result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
-                        mDisplayEventConnections.size(),
-                        mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
+                        mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
     for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
         sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
         result.appendFormat("    %p: count=%d\n", connection.get(),
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 9c13ed2..a0262b2 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -16,9 +16,11 @@
 
 #pragma once
 
-#include <stdint.h>
 #include <sys/types.h>
+
+#include <array>
 #include <condition_variable>
+#include <cstdint>
 #include <mutex>
 #include <thread>
 
@@ -31,8 +33,6 @@
 #include <utils/Errors.h>
 #include <utils/SortedVector.h>
 
-#include "DisplayDevice.h"
-
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -59,6 +59,9 @@
 
 class EventThread {
 public:
+    // TODO: Remove once stable display IDs are plumbed through SF/WM interface.
+    enum class DisplayType { Primary, External };
+
     virtual ~EventThread();
 
     virtual sp<BnDisplayEventConnection> createEventConnection() const = 0;
@@ -70,7 +73,7 @@
     virtual void onScreenAcquired() = 0;
 
     // called when receiving a hotplug event
-    virtual void onHotplugReceived(int type, bool connected) = 0;
+    virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0;
 
     virtual void dump(String8& result) const = 0;
 
@@ -122,7 +125,7 @@
     void onScreenAcquired() override;
 
     // called when receiving a hotplug event
-    void onHotplugReceived(int type, bool connected) override;
+    void onHotplugReceived(DisplayType displayType, bool connected) override;
 
     void dump(String8& result) const override;
 
@@ -155,8 +158,7 @@
     // protected by mLock
     SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
     Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
-    DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES] GUARDED_BY(
-            mMutex);
+    std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);
     bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
     bool mVsyncEnabled GUARDED_BY(mMutex) = false;
     bool mKeepRunning GUARDED_BY(mMutex) = true;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f148759..b4b3f4a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -363,7 +363,7 @@
     return reduce(floatWin, activeTransparentRegion);
 }
 
-Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const {
+Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const {
     // the crop is the area of the window that gets cropped, but not
     // scaled in any ways.
     const State& s(getDrawingState());
@@ -382,7 +382,7 @@
 
     Transform t = getTransform();
     activeCrop = t.transform(activeCrop);
-    if (!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
+    if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
         activeCrop.clear();
     }
     if (!s.finalCrop.isEmpty()) {
@@ -393,14 +393,14 @@
 
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
-        auto parentCrop = p->computeInitialCrop(hw);
+        auto parentCrop = p->computeInitialCrop(display);
         activeCrop.intersect(parentCrop, &activeCrop);
     }
 
     return activeCrop;
 }
 
-FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
+FloatRect Layer::computeCrop(const sp<const DisplayDevice>& display) const {
     // the content crop is the area of the content that gets scaled to the
     // layer's size. This is in buffer space.
     FloatRect crop = getContentCrop().toFloatRect();
@@ -409,7 +409,7 @@
     const State& s(getDrawingState());
 
     // Screen space to make reduction to parent crop clearer.
-    Rect activeCrop = computeInitialCrop(hw);
+    Rect activeCrop = computeInitialCrop(display);
     Transform t = getTransform();
     // Back to layer space to work with the content crop.
     activeCrop = t.inverse().transform(activeCrop);
@@ -482,6 +482,11 @@
 
 void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
     const auto displayId = display->getId();
+    if (!hasHwcLayer(displayId)) {
+        ALOGE("[%s] failed to setGeometry: no HWC layer found (%d)",
+              mName.string(), displayId);
+        return;
+    }
     auto& hwcInfo = getBE().mHwcLayers[displayId];
 
     // enable this layer
@@ -1371,13 +1376,13 @@
     return usage;
 }
 
-void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
+void Layer::updateTransformHint(const sp<const DisplayDevice>& display) const {
     uint32_t orientation = 0;
     if (!mFlinger->mDebugDisableTransformHint) {
         // The transform hint is used to improve performance, but we can
         // only have a single transform hint, it cannot
         // apply to all displays.
-        const Transform& planeTransform(hw->getTransform());
+        const Transform& planeTransform = display->getTransform();
         orientation = planeTransform.getOrientation();
         if (orientation & Transform::ROT_INVALID) {
             orientation = 0;
@@ -1438,15 +1443,18 @@
 }
 
 void Layer::miniDumpHeader(String8& result) {
-    result.append("----------------------------------------");
-    result.append("---------------------------------------\n");
+    result.append("-------------------------------");
+    result.append("-------------------------------");
+    result.append("-----------------------------\n");
     result.append(" Layer name\n");
     result.append("           Z | ");
     result.append(" Comp Type | ");
+    result.append(" Transform | ");
     result.append("  Disp Frame (LTRB) | ");
     result.append("         Source Crop (LTRB)\n");
-    result.append("----------------------------------------");
-    result.append("---------------------------------------\n");
+    result.append("-------------------------------");
+    result.append("-------------------------------");
+    result.append("-----------------------------\n");
 }
 
 void Layer::miniDump(String8& result, int32_t displayId) const {
@@ -1475,13 +1483,15 @@
         result.appendFormat("  %10d | ", layerState.z);
     }
     result.appendFormat("%10s | ", to_string(getCompositionType(displayId)).c_str());
+    result.appendFormat("%10s | ", to_string(hwcInfo.transform).c_str());
     const Rect& frame = hwcInfo.displayFrame;
     result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
     const FloatRect& crop = hwcInfo.sourceCrop;
     result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right, crop.bottom);
 
-    result.append("- - - - - - - - - - - - - - - - - - - - ");
-    result.append("- - - - - - - - - - - - - - - - - - - -\n");
+    result.append("- - - - - - - - - - - - - - - -");
+    result.append("- - - - - - - - - - - - - - - -");
+    result.append("- - - - - - - - - - - - - - -\n");
 }
 
 void Layer::dumpFrameStats(String8& result) const {
@@ -1964,6 +1974,8 @@
     auto buffer = getBE().compositionInfo.mBuffer;
     if (buffer != nullptr) {
         LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
+        LayerProtoHelper::writeToProto(Transform(mCurrentTransform),
+                                       layerInfo->mutable_buffer_transform());
     }
 
     layerInfo->set_queued_frames(getQueuedFrameCount());
@@ -1973,6 +1985,10 @@
 }
 
 void Layer::writeToProto(LayerProto* layerInfo, int32_t displayId) {
+    if (!hasHwcLayer(displayId)) {
+        return;
+    }
+
     writeToProto(layerInfo, LayerVector::StateSet::Drawing);
 
     const auto& hwcInfo = getBE().mHwcLayers.at(displayId);
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index fe953cd..fb94058 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -328,7 +328,7 @@
     HWC2::Composition getCompositionType(int32_t displayId) const;
     void setClearClientTarget(int32_t displayId, bool clear);
     bool getClearClientTarget(int32_t displayId) const;
-    void updateCursorPosition(const sp<const DisplayDevice>& hw);
+    void updateCursorPosition(const sp<const DisplayDevice>& display);
 
     /*
      * called after page-flip
@@ -425,7 +425,7 @@
 
     // Updates the transform hint in our SurfaceFlingerConsumer to match
     // the current orientation of the display device.
-    void updateTransformHint(const sp<const DisplayDevice>& hw) const;
+    void updateTransformHint(const sp<const DisplayDevice>& display) const;
 
     /*
      * returns the rectangle that crops the content of the layer and scales it
@@ -556,12 +556,12 @@
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
-    FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
+    FloatRect computeCrop(const sp<const DisplayDevice>& display) const;
     // Compute the initial crop as specified by parent layers and the
     // SurfaceControl for this layer. Does not include buffer crop from the
     // IGraphicBufferProducer client, as that should not affect child clipping.
     // Returns in screen space.
-    Rect computeInitialCrop(const sp<const DisplayDevice>& hw) const;
+    Rect computeInitialCrop(const sp<const DisplayDevice>& display) const;
 
     // drawing
     void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index dec1178..e39e623 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -332,11 +332,26 @@
     auto listSize = property_get_int32("debug.sf.max_igbp_list_size", int32_t(defaultListSize));
     mMaxGraphicBufferProducerListSize = (listSize > 0) ? size_t(listSize) : defaultListSize;
 
-    property_get("debug.sf.early_phase_offset_ns", value, "0");
-    const int earlyWakeupOffsetOffsetNs = atoi(value);
-    ALOGI_IF(earlyWakeupOffsetOffsetNs != 0, "Enabling separate early offset");
-    mVsyncModulator.setPhaseOffsets(sfVsyncPhaseOffsetNs - earlyWakeupOffsetOffsetNs,
-            sfVsyncPhaseOffsetNs);
+    property_get("debug.sf.early_phase_offset_ns", value, "-1");
+    const int earlySfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_phase_offset_ns", value, "-1");
+    const int earlyGlSfOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_app_phase_offset_ns", value, "-1");
+    const int earlyAppOffsetNs = atoi(value);
+
+    property_get("debug.sf.early_gl_app_phase_offset_ns", value, "-1");
+    const int earlyGlAppOffsetNs = atoi(value);
+
+    const VSyncModulator::Offsets earlyOffsets =
+            {earlySfOffsetNs != -1 ? earlySfOffsetNs : sfVsyncPhaseOffsetNs,
+            earlyAppOffsetNs != -1 ? earlyAppOffsetNs : vsyncPhaseOffsetNs};
+    const VSyncModulator::Offsets earlyGlOffsets =
+            {earlyGlSfOffsetNs != -1 ? earlyGlSfOffsetNs : sfVsyncPhaseOffsetNs,
+            earlyGlAppOffsetNs != -1 ? earlyGlAppOffsetNs : vsyncPhaseOffsetNs};
+    mVsyncModulator.setPhaseOffsets(earlyOffsets, earlyGlOffsets,
+            {sfVsyncPhaseOffsetNs, vsyncPhaseOffsetNs});
 
     // We should be reading 'persist.sys.sf.color_saturation' here
     // but since /data may be encrypted, we need to wait until after vold
@@ -651,7 +666,7 @@
                                                 },
                                                 "sfEventThread");
     mEventQueue->setEventThread(mSFEventThread.get());
-    mVsyncModulator.setEventThread(mSFEventThread.get());
+    mVsyncModulator.setEventThreads(mSFEventThread.get(), mEventThread.get());
 
     // Get a RenderEngine for the given display / config (can't fail)
     getBE().mRenderEngine =
@@ -668,12 +683,14 @@
     getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
     // Process any initial hotplug and resulting display changes.
     processDisplayHotplugEventsLocked();
-    LOG_ALWAYS_FATAL_IF(!getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY),
-            "Registered composer callback but didn't create the default primary display");
+    const auto display = getDefaultDisplayDeviceLocked();
+    LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
+    LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getId()),
+                        "Internal display is disconnected.");
 
     // make the default display GLContext current so that we can create textures
     // when creating Layers (which may happens before we render something)
-    getDefaultDisplayDeviceLocked()->makeCurrent();
+    display->makeCurrent();
 
     if (useVrFlinger) {
         auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
@@ -689,9 +706,11 @@
                 signalTransaction();
             }));
         };
-        mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
-                getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
-                vrFlingerRequestDisplayCallback);
+        mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
+                                            getHwComposer()
+                                                    .getHwcDisplayId(display->getId())
+                                                    .value_or(0),
+                                            vrFlingerRequestDisplayCallback);
         if (!mVrFlinger) {
             ALOGE("Failed to start vrflinger");
         }
@@ -720,8 +739,8 @@
         ALOGE("Run StartPropertySetThread failed!");
     }
 
-    mLegacySrgbSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
-            Dataspace::SRGB_LINEAR);
+    mLegacySrgbSaturationMatrix =
+            getHwComposer().getDataspaceSaturationMatrix(display->getId(), Dataspace::SRGB_LINEAR);
 
     ALOGV("Done initializing");
 }
@@ -1207,7 +1226,6 @@
     Mutex::Autolock _l(mHWVsyncLock);
     if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
         mPrimaryDispSync.beginResync();
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
         mEventControlThread->setVsyncEnabled(true);
         mPrimaryHWVsyncEnabled = true;
     }
@@ -1224,7 +1242,12 @@
         return;
     }
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+    if (!getHwComposer().isConnected(displayId)) {
+        return;
+    }
+
+    const auto activeConfig = getHwComposer().getActiveConfig(displayId);
     const nsecs_t period = activeConfig->getVsyncPeriod();
 
     mPrimaryDispSync.reset();
@@ -1232,7 +1255,6 @@
 
     if (!mPrimaryHWVsyncEnabled) {
         mPrimaryDispSync.beginResync();
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
         mEventControlThread->setVsyncEnabled(true);
         mPrimaryHWVsyncEnabled = true;
     }
@@ -1241,7 +1263,6 @@
 void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
     Mutex::Autolock _l(mHWVsyncLock);
     if (mPrimaryHWVsyncEnabled) {
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
         mEventControlThread->setVsyncEnabled(false);
         mPrimaryDispSync.endResync();
         mPrimaryHWVsyncEnabled = false;
@@ -1263,8 +1284,8 @@
     sLastResyncAttempted = now;
 }
 
-void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
-        hwc2_display_t displayId, int64_t timestamp) {
+void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
+                                     int64_t timestamp) {
     Mutex::Autolock lock(mStateLock);
     // Ignore any vsyncs from a previous hardware composer.
     if (sequenceId != getBE().mComposerSequenceId) {
@@ -1272,7 +1293,7 @@
     }
 
     int32_t type;
-    if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
+    if (!getBE().mHwc->onVsync(hwcDisplayId, timestamp, &type)) {
         return;
     }
 
@@ -1297,9 +1318,9 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                                        HWC2::Connection connection) {
-    ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+    ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
           connection == HWC2::Connection::Connected ? "connected" : "disconnected");
 
     // Ignore events that do not have the right sequenceId.
@@ -1313,7 +1334,7 @@
     // acquire it here.
     ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
 
-    mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
+    mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
 
     if (std::this_thread::get_id() == mMainThreadId) {
         // Process all pending hot plug events immediately if we are on the main thread.
@@ -1323,8 +1344,7 @@
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
-void SurfaceFlinger::onRefreshReceived(int sequenceId,
-                                       hwc2_display_t /*display*/) {
+void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
     Mutex::Autolock lock(mStateLock);
     if (sequenceId != getBE().mComposerSequenceId) {
         return;
@@ -1369,7 +1389,9 @@
 
     Mutex::Autolock _l(mStateLock);
 
-    int currentDisplayPowerMode = getDefaultDisplayDeviceLocked()->getPowerMode();
+    const auto display = getDefaultDisplayDeviceLocked();
+    LOG_ALWAYS_FATAL_IF(!display);
+    const int currentDisplayPowerMode = display->getPowerMode();
 
     if (!vrFlingerRequestsDisplay) {
         mVrFlinger->SeizeDisplayOwnership();
@@ -1394,11 +1416,10 @@
     invalidateHwcGeometry();
 
     // Re-enable default display.
-    setPowerModeInternal(getDefaultDisplayDeviceLocked(), currentDisplayPowerMode,
-                         /*stateLockHeld*/ true);
+    setPowerModeInternal(display, currentDisplayPowerMode, /*stateLockHeld*/ true);
 
     // Reset the timing values to account for the period of the swapped in HWC
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -1481,8 +1502,6 @@
     doComposition();
     postComposition(refreshStartTime);
 
-    mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
-
     mHadClientComposition = false;
     for (const auto& [token, display] : mDisplays) {
         mHadClientComposition = mHadClientComposition ||
@@ -1649,7 +1668,7 @@
 
     getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
-    if (display && getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+    if (display && getHwComposer().hasClientComposition(display->getId())) {
         glCompositionDoneFenceTime =
                 std::make_shared<FenceTime>(display->getClientTargetAcquireFence());
         getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
@@ -1658,8 +1677,9 @@
     }
 
     getBE().mDisplayTimeline.updateSignalTimes();
-    sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
-    auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+    mPreviousPresentFence =
+            display ? getHwComposer().getPresentFence(display->getId()) : Fence::NO_FENCE;
+    auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
@@ -1694,7 +1714,7 @@
     }
 
     if (!hasSyncFramework) {
-        if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) && display->isPoweredOn()) {
+        if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
             enableHardwareVsync();
         }
     }
@@ -1705,11 +1725,10 @@
         if (presentFenceTime->isValid()) {
             mAnimFrameTracker.setActualPresentFence(
                     std::move(presentFenceTime));
-        } else if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+        } else if (display && getHwComposer().isConnected(display->getId())) {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
-            nsecs_t presentTime =
-                    getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+            const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(display->getId());
             mAnimFrameTracker.setActualPresentTime(presentTime);
         }
         mAnimFrameTracker.advanceFrame();
@@ -1720,7 +1739,7 @@
         mTimeStats.incrementClientCompositionFrames();
     }
 
-    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) &&
+    if (display && getHwComposer().isConnected(display->getId()) &&
         display->getPowerMode() == HWC_POWER_MODE_OFF) {
         return;
     }
@@ -2070,8 +2089,9 @@
     mDebugInSwapBuffers = 0;
 
     // |mStateLock| not needed as we are on the main thread
-    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
-        uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+    const auto display = getDefaultDisplayDeviceLocked();
+    if (display && getHwComposer().isConnected(display->getId())) {
+        const uint32_t flipCount = display->getPageFlipCount();
         if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
             logFrameStats();
         }
@@ -2135,9 +2155,9 @@
 
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
     for (const auto& event : mPendingHotplugEvents) {
-        auto displayType = determineDisplayType(event.display, event.connection);
+        auto displayType = determineDisplayType(event.hwcDisplayId, event.connection);
         if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
-            ALOGW("Unable to determine the display type for display %" PRIu64, event.display);
+            ALOGW("Unable to determine the display type for display %" PRIu64, event.hwcDisplayId);
             continue;
         }
 
@@ -2147,9 +2167,9 @@
         }
 
         const auto displayId =
-                getBE().mHwc->onHotplug(event.display, displayType, event.connection);
+                getBE().mHwc->onHotplug(event.hwcDisplayId, displayType, event.connection);
         if (displayId) {
-            ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.display, *displayId);
+            ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.hwcDisplayId, *displayId);
         }
 
         if (event.connection == HWC2::Connection::Connected) {
@@ -2294,8 +2314,11 @@
                 if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
                     display->disconnect(getHwComposer());
                 }
-                if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
-                    mEventThread->onHotplugReceived(draw[i].type, false);
+                if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
+                    mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+                } else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
+                    mEventThread->onHotplugReceived(EventThread::DisplayType::External, false);
+                }
                 mDisplays.erase(draw.keyAt(i));
             } else {
                 // this display is in both lists. see if something changed.
@@ -2396,7 +2419,13 @@
                                       setupNewDisplayDeviceInternal(displayToken, displayId, state,
                                                                     dispSurface, producer));
                     if (!state.isVirtual()) {
-                        mEventThread->onHotplugReceived(state.type, true);
+                        if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+                            mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
+                                                            true);
+                        } else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+                            mEventThread->onHotplugReceived(EventThread::DisplayType::External,
+                                                            true);
+                        }
                     }
                 }
             }
@@ -2845,8 +2874,9 @@
             getRenderEngine().resetCurrentSurface();
 
             // |mStateLock| not needed as we are on the main thread
-            if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
-              ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
+            const auto defaultDisplay = getDefaultDisplayDeviceLocked();
+            if (!defaultDisplay || !defaultDisplay->makeCurrent()) {
+                ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
             }
             return false;
         }
@@ -3190,53 +3220,51 @@
     }
 }
 
-uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
-{
-    ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
-    if (dpyIdx < 0)
-        return 0;
+uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
+    const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
+    if (index < 0) return 0;
 
     uint32_t flags = 0;
-    DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
-    if (disp.isValid()) {
-        const uint32_t what = s.what;
-        if (what & DisplayState::eSurfaceChanged) {
-            if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
-                disp.surface = s.surface;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eLayerStackChanged) {
-            if (disp.layerStack != s.layerStack) {
-                disp.layerStack = s.layerStack;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eDisplayProjectionChanged) {
-            if (disp.orientation != s.orientation) {
-                disp.orientation = s.orientation;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.frame != s.frame) {
-                disp.frame = s.frame;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.viewport != s.viewport) {
-                disp.viewport = s.viewport;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eDisplaySizeChanged) {
-            if (disp.width != s.width) {
-                disp.width = s.width;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.height != s.height) {
-                disp.height = s.height;
-                flags |= eDisplayTransactionNeeded;
-            }
+    DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);
+
+    const uint32_t what = s.what;
+    if (what & DisplayState::eSurfaceChanged) {
+        if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
+            state.surface = s.surface;
+            flags |= eDisplayTransactionNeeded;
         }
     }
+    if (what & DisplayState::eLayerStackChanged) {
+        if (state.layerStack != s.layerStack) {
+            state.layerStack = s.layerStack;
+            flags |= eDisplayTransactionNeeded;
+        }
+    }
+    if (what & DisplayState::eDisplayProjectionChanged) {
+        if (state.orientation != s.orientation) {
+            state.orientation = s.orientation;
+            flags |= eDisplayTransactionNeeded;
+        }
+        if (state.frame != s.frame) {
+            state.frame = s.frame;
+            flags |= eDisplayTransactionNeeded;
+        }
+        if (state.viewport != s.viewport) {
+            state.viewport = s.viewport;
+            flags |= eDisplayTransactionNeeded;
+        }
+    }
+    if (what & DisplayState::eDisplaySizeChanged) {
+        if (state.width != s.width) {
+            state.width = s.width;
+            flags |= eDisplayTransactionNeeded;
+        }
+        if (state.height != s.height) {
+            state.height = s.height;
+            flags |= eDisplayTransactionNeeded;
+        }
+    }
+
     return flags;
 }
 
@@ -3570,13 +3598,16 @@
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::onInitializeDisplays() {
+    const auto displayToken = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+    if (!displayToken) return;
+
     // reset screen orientation and use primary layer stack
     Vector<ComposerState> state;
     Vector<DisplayState> displays;
     DisplayState d;
     d.what = DisplayState::eDisplayProjectionChanged |
              DisplayState::eLayerStackChanged;
-    d.token = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+    d.token = displayToken;
     d.layerStack = 0;
     d.orientation = DisplayState::eOrientationDefault;
     d.frame.makeInvalid();
@@ -3585,10 +3616,13 @@
     d.height = 0;
     displays.add(d);
     setTransactionState(state, displays, 0);
-    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
-                         /*stateLockHeld*/ false);
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto display = getDisplayDevice(displayToken);
+    if (!display) return;
+
+    setPowerModeInternal(display, HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false);
+
+    const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -3859,9 +3893,12 @@
         index++;
     }
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-    const nsecs_t period = activeConfig->getVsyncPeriod();
-    result.appendFormat("%" PRId64 "\n", period);
+    if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+        getHwComposer().isConnected(displayId)) {
+        const auto activeConfig = getBE().mHwc->getActiveConfig(displayId);
+        const nsecs_t period = activeConfig->getVsyncPeriod();
+        result.appendFormat("%" PRId64 "\n", period);
+    }
 
     if (name.isEmpty()) {
         mAnimFrameTracker.dumpStats(result);
@@ -4142,15 +4179,32 @@
     result.append(SyncFeatures::getInstance().toString());
     result.append("\n");
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-
     colorizer.bold(result);
-    result.append("DispSync configuration: ");
+    result.append("DispSync configuration:\n");
     colorizer.reset(result);
-    result.appendFormat("app phase %" PRId64 " ns, sf phase %" PRId64 " ns, early sf phase %" PRId64
-        " ns, present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-        vsyncPhaseOffsetNs, sfVsyncPhaseOffsetNs, mVsyncModulator.getEarlyPhaseOffset(),
-        dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+
+    const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
+    const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
+    if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+        getHwComposer().isConnected(displayId)) {
+        const auto activeConfig = getHwComposer().getActiveConfig(displayId);
+        result.appendFormat("Display %d: "
+                "app phase %" PRId64 " ns, "
+                "sf phase %" PRId64 " ns, "
+                "early app phase %" PRId64 " ns, "
+                "early sf phase %" PRId64 " ns, "
+                "early app gl phase %" PRId64 " ns, "
+                "early sf gl phase %" PRId64 " ns, "
+                "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+                displayId,
+                vsyncPhaseOffsetNs,
+                sfVsyncPhaseOffsetNs,
+                appEarlyOffset,
+                sfEarlyOffset,
+                appEarlyGlOffset,
+                sfEarlyOffset,
+                dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+    }
     result.append("\n");
 
     // Dump static screen stats
@@ -4206,22 +4260,21 @@
         result.appendFormat("  orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
                             display->isPoweredOn());
     }
-    result.appendFormat(
-            "  last eglSwapBuffers() time: %f us\n"
-            "  last transaction time     : %f us\n"
-            "  transaction-flags         : %08x\n"
-            "  refresh-rate              : %f fps\n"
-            "  x-dpi                     : %f\n"
-            "  y-dpi                     : %f\n"
-            "  gpu_to_cpu_unsupported    : %d\n"
-            ,
-            mLastSwapBufferTime/1000.0,
-            mLastTransactionTime/1000.0,
-            mTransactionFlags,
-            1e9 / activeConfig->getVsyncPeriod(),
-            activeConfig->getDpiX(),
-            activeConfig->getDpiY(),
-            !mGpuToCpuSupported);
+    result.appendFormat("  last eglSwapBuffers() time: %f us\n"
+                        "  last transaction time     : %f us\n"
+                        "  transaction-flags         : %08x\n"
+                        "  gpu_to_cpu_unsupported    : %d\n",
+                        mLastSwapBufferTime / 1000.0, mLastTransactionTime / 1000.0,
+                        mTransactionFlags, !mGpuToCpuSupported);
+
+    if (display) {
+        const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+        result.appendFormat("  refresh-rate              : %f fps\n"
+                            "  x-dpi                     : %f\n"
+                            "  y-dpi                     : %f\n",
+                            1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
+                            activeConfig->getDpiY());
+    }
 
     result.appendFormat("  eglSwapBuffers time: %f us\n",
             inSwapBuffersDuration/1000.0);
@@ -4279,19 +4332,15 @@
 
 const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int32_t displayId) {
     // Note: mStateLock is held here
-    wp<IBinder> displayToken;
     for (const auto& [token, display] : mDisplays) {
         if (display->getId() == displayId) {
-            displayToken = token;
-            break;
+            return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
         }
     }
-    if (displayToken == nullptr) {
-        ALOGE("getLayerSortedByZForHwcDisplay: Invalid display %d", displayId);
-        // Just use the primary display so we have something to return
-        displayToken = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
-    }
-    return getDisplayDeviceLocked(displayToken)->getVisibleLayersSortedByZ();
+
+    ALOGE("%s: Invalid display %d", __FUNCTION__, displayId);
+    static const Vector<sp<Layer>> empty;
+    return empty;
 }
 
 bool SurfaceFlinger::startDdmConnection()
@@ -4466,6 +4515,10 @@
                 return NO_ERROR;
             case 1013: {
                 const auto display = getDefaultDisplayDevice();
+                if (!display) {
+                    return NAME_NOT_FOUND;
+                }
+
                 reply->writeInt32(display->getPageFlipCount());
                 return NO_ERROR;
             }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 48c3f73..87e0699 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -457,11 +457,11 @@
     /* ------------------------------------------------------------------------
      * HWC2::ComposerCallback / HWComposer::EventHandler interface
      */
-    void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
+    void onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                          int64_t timestamp) override;
-    void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+    void onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                            HWC2::Connection connection) override;
-    void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
+    void onRefreshReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId) override;
 
     /* ------------------------------------------------------------------------
      * Message handling
@@ -665,8 +665,7 @@
     void logLayerStats();
     void doDisplayComposition(const sp<const DisplayDevice>& display, const Region& dirtyRegion);
 
-    // compose surfaces for display hw. this fails if using GL and the surface
-    // has been destroyed and is no longer valid.
+    // This fails if using GL and the surface has been destroyed.
     bool doComposeSurfaces(const sp<const DisplayDevice>& display);
 
     void postFramebuffer();
@@ -675,8 +674,8 @@
     /* ------------------------------------------------------------------------
      * Display management
      */
-    DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display,
-            HWC2::Connection connection) const;
+    DisplayDevice::DisplayType determineDisplayType(hwc2_display_t hwcDisplayId,
+                                                    HWC2::Connection connection) const;
     sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
                                                     int32_t displayId,
                                                     const DisplayDeviceState& state,
@@ -802,7 +801,7 @@
     bool mHadClientComposition = false;
 
     struct HotplugEvent {
-        hwc2_display_t display;
+        hwc2_display_t hwcDisplayId;
         HWC2::Connection connection = HWC2::Connection::Invalid;
     };
     // protected by mStateLock
diff --git a/services/surfaceflinger/VSyncModulator.h b/services/surfaceflinger/VSyncModulator.h
index d526313..e071a59 100644
--- a/services/surfaceflinger/VSyncModulator.h
+++ b/services/surfaceflinger/VSyncModulator.h
@@ -36,6 +36,11 @@
 
 public:
 
+    struct Offsets {
+        nsecs_t sf;
+        nsecs_t app;
+    };
+
     enum TransactionStart {
         EARLY,
         NORMAL
@@ -43,21 +48,32 @@
 
     // Sets the phase offsets
     //
-    // early: the phase offset when waking up early. May be the same as late, in which case we don't
-    //        shift offsets.
-    // late: the regular sf phase offset.
-    void setPhaseOffsets(nsecs_t early, nsecs_t late) {
-        mEarlyPhaseOffset = early;
-        mLatePhaseOffset = late;
-        mPhaseOffset = late;
+    // sfEarly: The phase offset when waking up SF early, which happens when marking a transaction
+    //          as early. May be the same as late, in which case we don't shift offsets.
+    // sfEarlyGl: Like sfEarly, but only if we used GL composition. If we use both GL composition
+    //            and the transaction was marked as early, we'll use sfEarly.
+    // sfLate: The regular SF vsync phase offset.
+    // appEarly: Like sfEarly, but for the app-vsync
+    // appEarlyGl: Like sfEarlyGl, but for the app-vsync.
+    // appLate: The regular app vsync phase offset.
+    void setPhaseOffsets(Offsets early, Offsets earlyGl, Offsets late) {
+        mEarlyOffsets = early;
+        mEarlyGlOffsets = earlyGl;
+        mLateOffsets = late;
+        mOffsets = late;
     }
 
-    nsecs_t getEarlyPhaseOffset() const {
-        return mEarlyPhaseOffset;
+    Offsets getEarlyOffsets() const {
+        return mEarlyOffsets;
     }
 
-    void setEventThread(EventThread* eventThread) {
-        mEventThread = eventThread;
+    Offsets getEarlyGlOffsets() const {
+        return mEarlyGlOffsets;
+    }
+
+    void setEventThreads(EventThread* sfEventThread, EventThread* appEventThread) {
+        mSfEventThread = sfEventThread;
+        mAppEventThread = appEventThread;
     }
 
     void setTransactionStart(TransactionStart transactionStart) {
@@ -71,63 +87,70 @@
             return;
         }
         mTransactionStart = transactionStart;
-        updatePhaseOffsets();
+        updateOffsets();
     }
 
     void onTransactionHandled() {
         if (mTransactionStart == TransactionStart::NORMAL) return;
         mTransactionStart = TransactionStart::NORMAL;
-        updatePhaseOffsets();
+        updateOffsets();
     }
 
     void onRefreshed(bool usedRenderEngine) {
-        bool updatePhaseOffsetsNeeded = false;
+        bool updateOffsetsNeeded = false;
         if (mRemainingEarlyFrameCount > 0) {
             mRemainingEarlyFrameCount--;
-            updatePhaseOffsetsNeeded = true;
+            updateOffsetsNeeded = true;
         }
         if (usedRenderEngine != mLastFrameUsedRenderEngine) {
             mLastFrameUsedRenderEngine = usedRenderEngine;
-            updatePhaseOffsetsNeeded = true;
+            updateOffsetsNeeded = true;
         }
-        if (updatePhaseOffsetsNeeded) {
-            updatePhaseOffsets();
+        if (updateOffsetsNeeded) {
+            updateOffsets();
         }
     }
 
 private:
 
-    void updatePhaseOffsets() {
+    void updateOffsets() {
+        const Offsets desired = getOffsets();
+        const Offsets current = mOffsets;
 
-        // Do not change phase offsets if disabled.
-        if (mEarlyPhaseOffset == mLatePhaseOffset) return;
+        bool changed = false;
+        if (desired.sf != current.sf) {
+            mSfEventThread->setPhaseOffset(desired.sf);
+            changed = true;
+        }
+        if (desired.app != current.app) {
+            mAppEventThread->setPhaseOffset(desired.app);
+            changed = true;
+        }
 
-        if (shouldUseEarlyOffset()) {
-            if (mPhaseOffset != mEarlyPhaseOffset) {
-                if (mEventThread) {
-                    mEventThread->setPhaseOffset(mEarlyPhaseOffset);
-                }
-                mPhaseOffset = mEarlyPhaseOffset;
-            }
-        } else {
-            if (mPhaseOffset != mLatePhaseOffset) {
-                if (mEventThread) {
-                    mEventThread->setPhaseOffset(mLatePhaseOffset);
-                }
-                mPhaseOffset = mLatePhaseOffset;
-            }
+        if (changed) {
+            mOffsets = desired;
         }
     }
 
-    bool shouldUseEarlyOffset() {
-        return mTransactionStart == TransactionStart::EARLY || mLastFrameUsedRenderEngine
-                || mRemainingEarlyFrameCount > 0;
+    Offsets getOffsets() {
+        if (mTransactionStart == TransactionStart::EARLY || mRemainingEarlyFrameCount > 0) {
+            return mEarlyOffsets;
+        } else if (mLastFrameUsedRenderEngine) {
+            return mEarlyGlOffsets;
+        } else {
+            return mLateOffsets;
+        }
     }
 
-    nsecs_t mLatePhaseOffset = 0;
-    nsecs_t mEarlyPhaseOffset = 0;
-    EventThread* mEventThread = nullptr;
-    std::atomic<nsecs_t> mPhaseOffset = 0;
+    Offsets mLateOffsets;
+    Offsets mEarlyOffsets;
+    Offsets mEarlyGlOffsets;
+
+    EventThread* mSfEventThread = nullptr;
+    EventThread* mAppEventThread = nullptr;
+
+    std::atomic<Offsets> mOffsets;
+
     std::atomic<TransactionStart> mTransactionStart = TransactionStart::NORMAL;
     std::atomic<bool> mLastFrameUsedRenderEngine = false;
     std::atomic<int> mRemainingEarlyFrameCount = 0;
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index fcf42f0..e1c0fd3 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -114,6 +114,7 @@
     layer->transform = generateTransform(layerProto.transform());
     layer->requestedTransform = generateTransform(layerProto.requested_transform());
     layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
+    layer->bufferTransform = generateTransform(layerProto.buffer_transform());
     layer->queuedFrames = layerProto.queued_frames();
     layer->refreshPending = layerProto.refresh_pending();
     layer->hwcFrame = generateRect(layerProto.hwc_frame());
@@ -312,6 +313,7 @@
     StringAppendF(&result, "      zOrderRelativeOf=%s\n",
                   zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str());
     StringAppendF(&result, "      activeBuffer=%s,", activeBuffer.to_string().c_str());
+    StringAppendF(&result, " tr=%s", bufferTransform.to_string().c_str());
     StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending);
     StringAppendF(&result, " windowType=%d, appId=%d", windowType, appId);
 
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 74a6f28..360e599 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -105,6 +105,7 @@
         Layer* parent = 0;
         Layer* zOrderRelativeOf = 0;
         LayerProtoParser::ActiveBuffer activeBuffer;
+        Transform bufferTransform;
         int32_t queuedFrames;
         bool refreshPending;
         LayerProtoParser::Rect hwcFrame;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index 77c6675..eb34694 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -80,6 +80,8 @@
   optional int32 hwc_composition_type = 35;
   // If it's a buffer layer, indicate if the content is protected
   optional bool is_protected = 36;
+  // If active_buffer is not null, record its transform
+  optional TransformProto buffer_transform = 37;
 }
 
 message PositionProto {
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 36424b9..df0c521 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*"
+            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*"
         }
 }
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index f2874d6..135d2af 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -42,7 +42,7 @@
 constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
 constexpr uint32_t SIZE_UPDATE = 134;
 constexpr uint32_t STACK_UPDATE = 1;
-constexpr uint64_t DEFERRED_UPDATE = 13;
+constexpr uint64_t DEFERRED_UPDATE = 0;
 constexpr float ALPHA_UPDATE = 0.29f;
 constexpr float POSITION_UPDATE = 121;
 const Rect CROP_UPDATE(16, 16, 32, 32);
@@ -97,30 +97,21 @@
     system("service call SurfaceFlinger 1020 i32 0 > /dev/null");
 }
 
-int32_t getSurfaceId(const std::string& surfaceName) {
-    enableInterceptor();
-    disableInterceptor();
-    Trace capturedTrace;
-    readProtoFile(&capturedTrace);
+int32_t getSurfaceId(const Trace& capturedTrace, const std::string& surfaceName) {
     int32_t layerId = 0;
-    for (const auto& increment : *capturedTrace.mutable_increment()) {
+    for (const auto& increment : capturedTrace.increment()) {
         if (increment.increment_case() == increment.kSurfaceCreation) {
             if (increment.surface_creation().name() == surfaceName) {
                 layerId = increment.surface_creation().id();
-                break;
             }
         }
     }
     return layerId;
 }
 
-int32_t getDisplayId(const std::string& displayName) {
-    enableInterceptor();
-    disableInterceptor();
-    Trace capturedTrace;
-    readProtoFile(&capturedTrace);
+int32_t getDisplayId(const Trace& capturedTrace, const std::string& displayName) {
     int32_t displayId = 0;
-    for (const auto& increment : *capturedTrace.mutable_increment()) {
+    for (const auto& increment : capturedTrace.increment()) {
         if (increment.increment_case() == increment.kDisplayCreation) {
             if (increment.display_creation().name() == displayName) {
                 displayId = increment.display_creation().id();
@@ -133,36 +124,15 @@
 
 class SurfaceInterceptorTest : public ::testing::Test {
 protected:
-    virtual void SetUp() {
+    void SetUp() override {
         // Allow SurfaceInterceptor write to /data
         system("setenforce 0");
 
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
-        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
-                ISurfaceComposer::eDisplayIdMain));
-        DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(display, &info);
-        ssize_t displayWidth = info.w;
-        ssize_t displayHeight = info.h;
-
-        // Background surface
-        mBGSurfaceControl = mComposerClient->createSurface(
-                String8(TEST_SURFACE_NAME), displayWidth, displayHeight,
-                PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(mBGSurfaceControl != nullptr);
-        ASSERT_TRUE(mBGSurfaceControl->isValid());
-        mBGLayerId = getSurfaceId(UNIQUE_TEST_SURFACE_NAME);
-
-        Transaction t;
-        t.setDisplayLayerStack(display, 0);
-        ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
-                .show(mBGSurfaceControl)
-                .apply());
     }
 
-    virtual void TearDown() {
+    void TearDown() override {
         mComposerClient->dispose();
         mBGSurfaceControl.clear();
         mComposerClient.clear();
@@ -171,18 +141,25 @@
     sp<SurfaceComposerClient> mComposerClient;
     sp<SurfaceControl> mBGSurfaceControl;
     int32_t mBGLayerId;
-    // Used to verify creation and destruction of surfaces and displays
-    int32_t mTargetId;
 
 public:
-    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-            bool (SurfaceInterceptorTest::* verification)(Trace *));
-    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-            SurfaceChange::SurfaceChangeCase changeCase);
-    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-            Increment::IncrementCase incrementCase);
-    void runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
-            bool intercepted = false);
+    using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&);
+    using TestAction = void (SurfaceInterceptorTest::*)();
+    using TestBooleanVerification = bool (SurfaceInterceptorTest::*)(const Trace&);
+    using TestVerification = void (SurfaceInterceptorTest::*)(const Trace&);
+
+    void setupBackgroundSurface();
+    void preProcessTrace(const Trace& trace);
+
+    // captureTest will enable SurfaceInterceptor, setup background surface,
+    // disable SurfaceInterceptor, collect the trace and process the trace for
+    // id of background surface before further verification.
+    void captureTest(TestTransactionAction action, TestBooleanVerification verification);
+    void captureTest(TestTransactionAction action, SurfaceChange::SurfaceChangeCase changeCase);
+    void captureTest(TestTransactionAction action, Increment::IncrementCase incrementCase);
+    void captureTest(TestAction action, TestBooleanVerification verification);
+    void captureTest(TestAction action, TestVerification verification);
+    void runInTransaction(TestTransactionAction action);
 
     // Verification of changes to a surface
     bool positionUpdateFound(const SurfaceChange& change, bool foundPosition);
@@ -199,18 +176,22 @@
     bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
     bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
     bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
-    bool surfaceUpdateFound(Trace* trace, SurfaceChange::SurfaceChangeCase changeCase);
-    void assertAllUpdatesFound(Trace* trace);
+    bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
+
+    // Find all of the updates in the single trace
+    void assertAllUpdatesFound(const Trace& trace);
 
     // Verification of creation and deletion of a surface
     bool surfaceCreationFound(const Increment& increment, bool foundSurface);
-    bool surfaceDeletionFound(const Increment& increment, bool foundSurface);
+    bool surfaceDeletionFound(const Increment& increment, const int32_t targetId,
+            bool foundSurface);
     bool displayCreationFound(const Increment& increment, bool foundDisplay);
-    bool displayDeletionFound(const Increment& increment, bool foundDisplay);
-    bool singleIncrementFound(Trace* trace, Increment::IncrementCase incrementCase);
+    bool displayDeletionFound(const Increment& increment, const int32_t targetId,
+            bool foundDisplay);
+    bool singleIncrementFound(const Trace& trace, Increment::IncrementCase incrementCase);
 
     // Verification of buffer updates
-    bool bufferUpdatesFound(Trace* trace);
+    bool bufferUpdatesFound(const Trace& trace);
 
     // Perform each of the possible changes to a surface
     void positionUpdate(Transaction&);
@@ -233,48 +214,93 @@
 
     void nBufferUpdates();
     void runAllUpdates();
+
+private:
+    void captureInTransaction(TestTransactionAction action, Trace*);
+    void capture(TestAction action, Trace*);
 };
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-        bool (SurfaceInterceptorTest::* verification)(Trace *))
-{
-    runInTransaction(action, true);
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE((this->*verification)(&capturedTrace));
+void SurfaceInterceptorTest::captureInTransaction(TestTransactionAction action, Trace* outTrace) {
+    enableInterceptor();
+    setupBackgroundSurface();
+    runInTransaction(action);
+    disableInterceptor();
+    ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
+    preProcessTrace(*outTrace);
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-        Increment::IncrementCase incrementCase)
-{
-    runInTransaction(action, true);
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(singleIncrementFound(&capturedTrace, incrementCase));
+void SurfaceInterceptorTest::capture(TestAction action, Trace* outTrace) {
+    enableInterceptor();
+    setupBackgroundSurface();
+    (this->*action)();
+    disableInterceptor();
+    ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
+    preProcessTrace(*outTrace);
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-        SurfaceChange::SurfaceChangeCase changeCase)
-{
-    runInTransaction(action, true);
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase));
+void SurfaceInterceptorTest::setupBackgroundSurface() {
+    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+    DisplayInfo info;
+    SurfaceComposerClient::getDisplayInfo(display, &info);
+    ssize_t displayWidth = info.w;
+    ssize_t displayHeight = info.h;
+
+    // Background surface
+    mBGSurfaceControl = mComposerClient->createSurface(
+            String8(TEST_SURFACE_NAME), displayWidth, displayHeight,
+            PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(mBGSurfaceControl != nullptr);
+    ASSERT_TRUE(mBGSurfaceControl->isValid());
+
+    Transaction t;
+    t.setDisplayLayerStack(display, 0);
+    ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
+            .show(mBGSurfaceControl)
+            .apply());
 }
 
-void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
-        bool intercepted)
-{
-    if (intercepted) {
-        enableInterceptor();
-    }
+void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
+    mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_SURFACE_NAME);
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+        TestBooleanVerification verification) {
+    Trace capturedTrace;
+    captureInTransaction(action, &capturedTrace);
+    ASSERT_TRUE((this->*verification)(capturedTrace));
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+        Increment::IncrementCase incrementCase) {
+    Trace capturedTrace;
+    captureInTransaction(action, &capturedTrace);
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, incrementCase));
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+        SurfaceChange::SurfaceChangeCase changeCase) {
+    Trace capturedTrace;
+    captureInTransaction(action, &capturedTrace);
+    ASSERT_TRUE(surfaceUpdateFound(capturedTrace, changeCase));
+}
+
+void SurfaceInterceptorTest::captureTest(TestAction action, TestBooleanVerification verification) {
+    Trace capturedTrace;
+    capture(action, &capturedTrace);
+    ASSERT_TRUE((this->*verification)(capturedTrace));
+}
+
+void SurfaceInterceptorTest::captureTest(TestAction action, TestVerification verification) {
+    Trace capturedTrace;
+    capture(action, &capturedTrace);
+    (this->*verification)(capturedTrace);
+}
+
+void SurfaceInterceptorTest::runInTransaction(TestTransactionAction action) {
     Transaction t;
     (this->*action)(t);
     t.apply(true);
-
-    if (intercepted) {
-        disableInterceptor();
-    }
 }
 
 void SurfaceInterceptorTest::positionUpdate(Transaction& t) {
@@ -342,7 +368,6 @@
 void SurfaceInterceptorTest::displayDeletion(Transaction&) {
     sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
     SurfaceComposerClient::destroyDisplay(testDisplay);
-    mTargetId = getDisplayId(DISPLAY_NAME.string());
 }
 
 void SurfaceInterceptorTest::runAllUpdates() {
@@ -383,9 +408,8 @@
     bool hasY(change.position().y() == POSITION_UPDATE);
     if (hasX && hasY && !foundPosition) {
         foundPosition = true;
-    }
-    // Failed because the position update was found a second time
-    else if (hasX && hasY && foundPosition) {
+    } else if (hasX && hasY && foundPosition) {
+        // Failed because the position update was found a second time
         [] () { FAIL(); }();
     }
     return foundPosition;
@@ -396,8 +420,7 @@
     bool hasHeight(change.size().w() == SIZE_UPDATE);
     if (hasWidth && hasHeight && !foundSize) {
         foundSize = true;
-    }
-    else if (hasWidth && hasHeight && foundSize) {
+    } else if (hasWidth && hasHeight && foundSize) {
         [] () { FAIL(); }();
     }
     return foundSize;
@@ -407,8 +430,7 @@
     bool hasAlpha(change.alpha().alpha() == ALPHA_UPDATE);
     if (hasAlpha && !foundAlpha) {
         foundAlpha = true;
-    }
-    else if (hasAlpha && foundAlpha) {
+    } else if (hasAlpha && foundAlpha) {
         [] () { FAIL(); }();
     }
     return foundAlpha;
@@ -418,8 +440,7 @@
     bool hasLayer(change.layer().layer() == LAYER_UPDATE);
     if (hasLayer && !foundLayer) {
         foundLayer = true;
-    }
-    else if (hasLayer && foundLayer) {
+    } else if (hasLayer && foundLayer) {
         [] () { FAIL(); }();
     }
     return foundLayer;
@@ -432,24 +453,21 @@
     bool hasBottom(change.crop().rectangle().bottom() == CROP_UPDATE.bottom);
     if (hasLeft && hasRight && hasTop && hasBottom && !foundCrop) {
         foundCrop = true;
-    }
-    else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
+    } else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
         [] () { FAIL(); }();
     }
     return foundCrop;
 }
 
 bool SurfaceInterceptorTest::finalCropUpdateFound(const SurfaceChange& change,
-        bool foundFinalCrop)
-{
+        bool foundFinalCrop) {
     bool hasLeft(change.final_crop().rectangle().left() == CROP_UPDATE.left);
     bool hasTop(change.final_crop().rectangle().top() == CROP_UPDATE.top);
     bool hasRight(change.final_crop().rectangle().right() == CROP_UPDATE.right);
     bool hasBottom(change.final_crop().rectangle().bottom() == CROP_UPDATE.bottom);
     if (hasLeft && hasRight && hasTop && hasBottom && !foundFinalCrop) {
         foundFinalCrop = true;
-    }
-    else if (hasLeft && hasRight && hasTop && hasBottom && foundFinalCrop) {
+    } else if (hasLeft && hasRight && hasTop && hasBottom && foundFinalCrop) {
         [] () { FAIL(); }();
     }
     return foundFinalCrop;
@@ -462,29 +480,25 @@
     bool hasTy((float)change.matrix().dtdy() == (float)-M_SQRT1_2);
     if (hasSx && hasTx && hasSy && hasTy && !foundMatrix) {
         foundMatrix = true;
-    }
-    else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
+    } else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
         [] () { FAIL(); }();
     }
     return foundMatrix;
 }
 
 bool SurfaceInterceptorTest::scalingModeUpdateFound(const SurfaceChange& change,
-        bool foundScalingMode)
-{
+        bool foundScalingMode) {
     bool hasScalingUpdate(change.override_scaling_mode().override_scaling_mode() == SCALING_UPDATE);
     if (hasScalingUpdate && !foundScalingMode) {
         foundScalingMode = true;
-    }
-    else if (hasScalingUpdate && foundScalingMode) {
+    } else if (hasScalingUpdate && foundScalingMode) {
         [] () { FAIL(); }();
     }
     return foundScalingMode;
 }
 
 bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const SurfaceChange& change,
-        bool foundTransparentRegion)
-{
+        bool foundTransparentRegion) {
     auto traceRegion = change.transparent_region_hint().region(0);
     bool hasLeft(traceRegion.left() == CROP_UPDATE.left);
     bool hasTop(traceRegion.top() == CROP_UPDATE.top);
@@ -492,84 +506,72 @@
     bool hasBottom(traceRegion.bottom() == CROP_UPDATE.bottom);
     if (hasLeft && hasRight && hasTop && hasBottom && !foundTransparentRegion) {
         foundTransparentRegion = true;
-    }
-    else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
+    } else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
         [] () { FAIL(); }();
     }
     return foundTransparentRegion;
 }
 
 bool SurfaceInterceptorTest::layerStackUpdateFound(const SurfaceChange& change,
-        bool foundLayerStack)
-{
+        bool foundLayerStack) {
     bool hasLayerStackUpdate(change.layer_stack().layer_stack() == STACK_UPDATE);
     if (hasLayerStackUpdate && !foundLayerStack) {
         foundLayerStack = true;
-    }
-    else if (hasLayerStackUpdate && foundLayerStack) {
+    } else if (hasLayerStackUpdate && foundLayerStack) {
         [] () { FAIL(); }();
     }
     return foundLayerStack;
 }
 
 bool SurfaceInterceptorTest::hiddenFlagUpdateFound(const SurfaceChange& change,
-        bool foundHiddenFlag)
-{
+        bool foundHiddenFlag) {
     bool hasHiddenFlag(change.hidden_flag().hidden_flag());
     if (hasHiddenFlag && !foundHiddenFlag) {
         foundHiddenFlag = true;
-    }
-    else if (hasHiddenFlag && foundHiddenFlag) {
+    } else if (hasHiddenFlag && foundHiddenFlag) {
         [] () { FAIL(); }();
     }
     return foundHiddenFlag;
 }
 
 bool SurfaceInterceptorTest::opaqueFlagUpdateFound(const SurfaceChange& change,
-        bool foundOpaqueFlag)
-{
+        bool foundOpaqueFlag) {
     bool hasOpaqueFlag(change.opaque_flag().opaque_flag());
     if (hasOpaqueFlag && !foundOpaqueFlag) {
         foundOpaqueFlag = true;
-    }
-    else if (hasOpaqueFlag && foundOpaqueFlag) {
+    } else if (hasOpaqueFlag && foundOpaqueFlag) {
         [] () { FAIL(); }();
     }
     return foundOpaqueFlag;
 }
 
 bool SurfaceInterceptorTest::secureFlagUpdateFound(const SurfaceChange& change,
-        bool foundSecureFlag)
-{
+        bool foundSecureFlag) {
     bool hasSecureFlag(change.secure_flag().secure_flag());
     if (hasSecureFlag && !foundSecureFlag) {
         foundSecureFlag = true;
-    }
-    else if (hasSecureFlag && foundSecureFlag) {
+    } else if (hasSecureFlag && foundSecureFlag) {
         [] () { FAIL(); }();
     }
     return foundSecureFlag;
 }
 
 bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const SurfaceChange& change,
-        bool foundDeferred)
-{
+        bool foundDeferred) {
     bool hasId(change.deferred_transaction().layer_id() == mBGLayerId);
     bool hasFrameNumber(change.deferred_transaction().frame_number() == DEFERRED_UPDATE);
     if (hasId && hasFrameNumber && !foundDeferred) {
         foundDeferred = true;
-    }
-    else if (hasId && hasFrameNumber && foundDeferred) {
+    } else if (hasId && hasFrameNumber && foundDeferred) {
         [] () { FAIL(); }();
     }
     return foundDeferred;
 }
 
-bool SurfaceInterceptorTest::surfaceUpdateFound(Trace* trace,
-        SurfaceChange::SurfaceChangeCase changeCase)
-{
+bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
+        SurfaceChange::SurfaceChangeCase changeCase) {
     bool foundUpdate = false;
-    for (const auto& increment : *trace->mutable_increment()) {
+    for (const auto& increment : trace.increment()) {
         if (increment.increment_case() == increment.kTransaction) {
             for (const auto& change : increment.transaction().surface_change()) {
                 if (change.id() == mBGLayerId && change.SurfaceChange_case() == changeCase) {
@@ -627,7 +629,7 @@
     return foundUpdate;
 }
 
-void SurfaceInterceptorTest::assertAllUpdatesFound(Trace* trace) {
+void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) {
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kPosition));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSize));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kAlpha));
@@ -650,19 +652,18 @@
             increment.surface_creation().h() == SIZE_UPDATE);
     if (isMatch && !foundSurface) {
         foundSurface = true;
-    }
-    else if (isMatch && foundSurface) {
+    } else if (isMatch && foundSurface) {
         [] () { FAIL(); }();
     }
     return foundSurface;
 }
 
-bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment, bool foundSurface) {
-    bool isMatch(increment.surface_deletion().id() == mTargetId);
+bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment,
+        const int32_t targetId, bool foundSurface) {
+    bool isMatch(increment.surface_deletion().id() == targetId);
     if (isMatch && !foundSurface) {
         foundSurface = true;
-    }
-    else if (isMatch && foundSurface) {
+    } else if (isMatch && foundSurface) {
         [] () { FAIL(); }();
     }
     return foundSurface;
@@ -673,42 +674,45 @@
             increment.display_creation().is_secure());
     if (isMatch && !foundDisplay) {
         foundDisplay = true;
-    }
-    else if (isMatch && foundDisplay) {
+    } else if (isMatch && foundDisplay) {
         [] () { FAIL(); }();
     }
     return foundDisplay;
 }
 
-bool SurfaceInterceptorTest::displayDeletionFound(const Increment& increment, bool foundDisplay) {
-    bool isMatch(increment.display_deletion().id() == mTargetId);
+bool SurfaceInterceptorTest::displayDeletionFound(const Increment& increment,
+        const int32_t targetId, bool foundDisplay) {
+    bool isMatch(increment.display_deletion().id() == targetId);
     if (isMatch && !foundDisplay) {
         foundDisplay = true;
-    }
-    else if (isMatch && foundDisplay) {
+    } else if (isMatch && foundDisplay) {
         [] () { FAIL(); }();
     }
     return foundDisplay;
 }
 
-bool SurfaceInterceptorTest::singleIncrementFound(Trace* trace,
-        Increment::IncrementCase incrementCase)
-{
+bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace,
+        Increment::IncrementCase incrementCase) {
     bool foundIncrement = false;
-    for (const auto& increment : *trace->mutable_increment()) {
+    for (const auto& increment : trace.increment()) {
         if (increment.increment_case() == incrementCase) {
+            int32_t targetId = 0;
             switch (incrementCase) {
                 case Increment::IncrementCase::kSurfaceCreation:
                     foundIncrement = surfaceCreationFound(increment, foundIncrement);
                     break;
                 case Increment::IncrementCase::kSurfaceDeletion:
-                    foundIncrement = surfaceDeletionFound(increment, foundIncrement);
+                    // Find the id of created surface.
+                    targetId = getSurfaceId(trace, UNIQUE_LAYER_NAME);
+                    foundIncrement = surfaceDeletionFound(increment, targetId, foundIncrement);
                     break;
                 case Increment::IncrementCase::kDisplayCreation:
                     foundIncrement = displayCreationFound(increment, foundIncrement);
                     break;
                 case Increment::IncrementCase::kDisplayDeletion:
-                    foundIncrement = displayDeletionFound(increment, foundIncrement);
+                    // Find the id of created display.
+                    targetId = getDisplayId(trace, DISPLAY_NAME.string());
+                    foundIncrement = displayDeletionFound(increment, targetId, foundIncrement);
                     break;
                 default:
                     /* code */
@@ -719,9 +723,9 @@
     return foundIncrement;
 }
 
-bool SurfaceInterceptorTest::bufferUpdatesFound(Trace* trace) {
+bool SurfaceInterceptorTest::bufferUpdatesFound(const Trace& trace) {
     uint32_t updates = 0;
-    for (const auto& inc : *trace->mutable_increment()) {
+    for (const auto& inc : trace.increment()) {
         if (inc.increment_case() == inc.kBufferUpdate && inc.buffer_update().id() == mBGLayerId) {
             updates++;
         }
@@ -795,14 +799,8 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
-    enableInterceptor();
-    runAllUpdates();
-    disableInterceptor();
-
-    // Find all of the updates in the single trace
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    assertAllUpdatesFound(&capturedTrace);
+    captureTest(&SurfaceInterceptorTest::runAllUpdates,
+                &SurfaceInterceptorTest::assertAllUpdatesFound);
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptSurfaceCreationWorks) {
@@ -811,16 +809,15 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptSurfaceDeletionWorks) {
+    enableInterceptor();
     sp<SurfaceControl> layerToDelete = mComposerClient->createSurface(String8(LAYER_NAME),
             SIZE_UPDATE, SIZE_UPDATE, PIXEL_FORMAT_RGBA_8888, 0);
-    this->mTargetId = getSurfaceId(UNIQUE_LAYER_NAME);
-    enableInterceptor();
     mComposerClient->destroySurface(layerToDelete->getHandle());
     disableInterceptor();
 
     Trace capturedTrace;
     ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(singleIncrementFound(&capturedTrace, Increment::IncrementCase::kSurfaceDeletion));
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceDeletion));
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptDisplayCreationWorks) {
@@ -829,23 +826,24 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) {
-    captureTest(&SurfaceInterceptorTest::displayDeletion,
-            Increment::IncrementCase::kDisplayDeletion);
-}
-
-TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
     enableInterceptor();
-    nBufferUpdates();
+    runInTransaction(&SurfaceInterceptorTest::displayDeletion);
     disableInterceptor();
     Trace capturedTrace;
     ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kDisplayDeletion));
+}
+
+TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
+    captureTest(&SurfaceInterceptorTest::nBufferUpdates,
+            &SurfaceInterceptorTest::bufferUpdatesFound);
 }
 
 // If the interceptor is enabled while buffer updates are being pushed, the interceptor should
 // first create a snapshot of the existing displays and surfaces and then start capturing
 // the buffer updates
 TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) {
+    setupBackgroundSurface();
     std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
     enableInterceptor();
     disableInterceptor();
@@ -859,6 +857,7 @@
 
 TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) {
     enableInterceptor();
+    setupBackgroundSurface();
     std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
     std::thread surfaceUpdates(&SurfaceInterceptorTest::runAllUpdates, this);
     runInTransaction(&SurfaceInterceptorTest::surfaceCreation);
@@ -868,10 +867,11 @@
 
     Trace capturedTrace;
     ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+    preProcessTrace(capturedTrace);
 
-    assertAllUpdatesFound(&capturedTrace);
-    ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
-    ASSERT_TRUE(singleIncrementFound(&capturedTrace, Increment::IncrementCase::kSurfaceCreation));
+    assertAllUpdatesFound(capturedTrace);
+    ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
 }
 
 }
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 1a7805a..3be2ad0 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -245,6 +245,8 @@
 
     // The type for this display
     static constexpr DisplayDevice::DisplayType TYPE = type;
+    static_assert(TYPE != DisplayDevice::DISPLAY_ID_INVALID);
+
     static constexpr DisplayDevice::DisplayType DISPLAY_ID = displayId;
 
     // When creating native window surfaces for the framebuffer, whether those should be critical
@@ -385,11 +387,6 @@
                                  DisplayVariant<type, type, width, height, critical, Async::FALSE,
                                                 Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
 
-// An invalid display
-using InvalidDisplayVariant =
-        DisplayVariant<DisplayDevice::DISPLAY_ID_INVALID, DisplayDevice::DISPLAY_ID_INVALID, 0, 0,
-                       Critical::FALSE, Async::FALSE, Secure::FALSE, 0>;
-
 // A primary display is a physical display that is critical
 using PrimaryDisplayVariant =
         PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
@@ -686,9 +683,7 @@
         Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
              HdrNotSupportedVariant<PrimaryDisplayVariant>,
              Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using InvalidDisplayCase = Case<InvalidDisplayVariant, WideColorSupportNotConfiguredVariant,
-                                NonHwcDisplayHdrSupportVariant,
-                                NoPerFrameMetadataSupportVariant<InvalidDisplayVariant>>;
+
 /* ------------------------------------------------------------------------
  *
  * SurfaceFlinger::onHotplugReceived
@@ -696,8 +691,8 @@
 
 TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
     constexpr int currentSequenceId = 123;
-    constexpr hwc2_display_t displayId1 = 456;
-    constexpr hwc2_display_t displayId2 = 654;
+    constexpr hwc2_display_t hwcDisplayId1 = 456;
+    constexpr hwc2_display_t hwcDisplayId2 = 654;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -720,8 +715,8 @@
     // Invocation
 
     // Simulate two hotplug events (a connect and a disconnect)
-    mFlinger.onHotplugReceived(currentSequenceId, displayId1, HWC2::Connection::Connected);
-    mFlinger.onHotplugReceived(currentSequenceId, displayId2, HWC2::Connection::Disconnected);
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, HWC2::Connection::Connected);
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, HWC2::Connection::Disconnected);
 
     // --------------------------------------------------------------------
     // Postconditions
@@ -732,9 +727,9 @@
     // All events should be in the pending event queue.
     const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
     ASSERT_EQ(2u, pendingEvents.size());
-    EXPECT_EQ(displayId1, pendingEvents[0].display);
+    EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
     EXPECT_EQ(HWC2::Connection::Connected, pendingEvents[0].connection);
-    EXPECT_EQ(displayId2, pendingEvents[1].display);
+    EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
     EXPECT_EQ(HWC2::Connection::Disconnected, pendingEvents[1].connection);
 }
 
@@ -1165,13 +1160,23 @@
     Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
 
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, true)).Times(1);
+    EXPECT_CALL(*mEventThread,
+                onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+                                          ? EventThread::DisplayType::Primary
+                                          : EventThread::DisplayType::External,
+                                  true))
+            .Times(1);
 }
 
 template <typename Case>
 void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, false)).Times(1);
+    EXPECT_CALL(*mEventThread,
+                onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+                                          ? EventThread::DisplayType::Primary
+                                          : EventThread::DisplayType::External,
+                                  false))
+            .Times(1);
 }
 
 template <typename Case>
@@ -1824,40 +1829,6 @@
     EXPECT_FALSE(hasCurrentDisplayState(displayToken));
 }
 
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithInvalidDisplay) {
-    using Case = InvalidDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // An invalid display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The invalid display has some state
-    display.mutableCurrentDisplayState().layerStack = 654u;
-
-    // The requested display state tries to change the display state.
-    DisplayState state;
-    state.what = DisplayState::eLayerStackChanged;
-    state.token = display.token();
-    state.layerStack = 456;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-
-    // The current display layer stack value is unchanged.
-    EXPECT_EQ(654u, getCurrentDisplayState(display.token()).layerStack);
-}
-
 TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
     using Case = SimplePrimaryDisplayCase;
 
@@ -2684,7 +2655,7 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The diplay is already set to HWC_POWER_MODE_NORMAL
+    // The display is already set to HWC_POWER_MODE_NORMAL
     display.mutableDisplayDevice()->setPowerMode(HWC_POWER_MODE_NORMAL);
 
     // --------------------------------------------------------------------
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 80fdb80..19747bd 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -71,7 +71,8 @@
                                               ConnectionEventRecorder& connectionEventRecorder,
                                               nsecs_t expectedTimestamp, unsigned expectedCount);
     void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
-    void expectHotplugEventReceivedByConnection(int expectedDisplayType, bool expectedConnected);
+    void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType,
+                                                bool expectedConnected);
 
     AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
     AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -169,13 +170,16 @@
                                          expectedCount);
 }
 
-void EventThreadTest::expectHotplugEventReceivedByConnection(int expectedDisplayType,
-                                                             bool expectedConnected) {
+void EventThreadTest::expectHotplugEventReceivedByConnection(
+        EventThread::DisplayType expectedDisplayType, bool expectedConnected) {
+    const uint32_t expectedDisplayId =
+            expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1;
+
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
     EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
-    EXPECT_EQ(static_cast<unsigned>(expectedDisplayType), event.header.id);
+    EXPECT_EQ(expectedDisplayId, event.header.id);
     EXPECT_EQ(expectedConnected, event.hotplug.connected);
 }
 
@@ -394,28 +398,23 @@
 }
 
 TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, false);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, false);
+    mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
 }
 
 TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, true);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, true);
+    mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
 }
 
 TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, false);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, false);
+    mThread->onHotplugReceived(EventThread::DisplayType::External, false);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false);
 }
 
 TEST_F(EventThreadTest, postHotplugExternalConnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, true);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, true);
-}
-
-TEST_F(EventThreadTest, postHotplugVirtualDisconnectIsFilteredOut) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_VIRTUAL, false);
-    EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+    mThread->onHotplugReceived(EventThread::DisplayType::External, true);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 5dcac92..ae5a100 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -91,8 +91,9 @@
 
     auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); }
 
-    auto setPowerModeInternal(const sp<DisplayDevice>& hw, int mode, bool stateLockHeld = false) {
-        return mFlinger->setPowerModeInternal(hw, mode, stateLockHeld);
+    auto setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
+                              bool stateLockHeld = false) {
+        return mFlinger->setPowerModeInternal(display, mode, stateLockHeld);
     }
 
     /* ------------------------------------------------------------------------
@@ -232,7 +233,7 @@
             display->mutableIsConnected() = true;
 
             ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
-            flinger->mutableHwcDisplayData()[mType].reset();
+            flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData();
             flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
             flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
 
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index e6ea663..df9bfc6 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -31,7 +31,7 @@
     MOCK_CONST_METHOD0(createEventConnection, sp<BnDisplayEventConnection>());
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
-    MOCK_METHOD2(onHotplugReceived, void(int, bool));
+    MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
     MOCK_CONST_METHOD1(dump, void(String8&));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
 };
diff --git a/services/vr/performanced/directory_reader.h b/services/vr/performanced/directory_reader.h
index b9d27c3..f8359c4 100644
--- a/services/vr/performanced/directory_reader.h
+++ b/services/vr/performanced/directory_reader.h
@@ -16,10 +16,11 @@
 class DirectoryReader {
  public:
   explicit DirectoryReader(base::unique_fd directory_fd) {
-    directory_ = fdopendir(directory_fd.get());
+    int fd = directory_fd.release();
+    directory_ = fdopendir(fd);
     error_ = errno;
-    if (directory_ != nullptr)
-      (void) directory_fd.release(); // ignore return result?
+    if (directory_ == nullptr)
+      close(fd);
   }
 
   ~DirectoryReader() {
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 4c26671..d304bac 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -124,9 +124,6 @@
   // TODO(eieio): Replace this witha device-specific config file. This is just a
   // hack for now to put some form of permission logic in place while a longer
   // term solution is developed.
-  using AllowRootSystem =
-      CheckAnd<SameProcess,
-               CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>;
   using AllowRootSystemGraphics =
       CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
                                     GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
@@ -170,17 +167,17 @@
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_low,
-        .permission_check = AllowRootSystem::Check}},
+        .permission_check = AllowRootSystemTrusted::Check}},
       {"sensors:low",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_low,
-        .permission_check = AllowRootSystem::Check}},
+        .permission_check = AllowRootSystemTrusted::Check}},
       {"sensors:high",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_low + 1,
-        .permission_check = AllowRootSystem::Check}},
+        .permission_check = AllowRootSystemTrusted::Check}},
       {"vr:system:arp",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,