Merge "Remove dumping raft logs"
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
new file mode 100644
index 0000000..f8f0265
--- /dev/null
+++ b/PREUPLOAD.cfg
@@ -0,0 +1,3 @@
+[Hook Scripts]
+owners_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "OWNERS$"
+installd_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "^cmds/installd/"
diff --git a/cmds/installd/OWNERS b/cmds/installd/OWNERS
new file mode 100644
index 0000000..50440f1
--- /dev/null
+++ b/cmds/installd/OWNERS
@@ -0,0 +1,7 @@
+set noparent
+
+calin@google.com
+agampe@google.com
+jsharkey@android.com
+toddke@google.com
+ngeoffray@google.com
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 6b340a8..d776682 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -403,7 +403,11 @@
 
     cb.func_audit = audit_callback;
     selinux_set_callback(SELINUX_CB_AUDIT, cb);
+#ifdef VENDORSERVICEMANAGER
+    cb.func_log = selinux_vendor_log_callback;
+#else
     cb.func_log = selinux_log_callback;
+#endif
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
 #ifdef VENDORSERVICEMANAGER
diff --git a/include/android/system_fonts.h b/include/android/system_fonts.h
new file mode 100644
index 0000000..79f666b
--- /dev/null
+++ b/include/android/system_fonts.h
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file system_fonts.h
+ * @brief Provides the system font configurations.
+ *
+ * These APIs provides the list of system installed font files with additional metadata about the
+ * font.
+ *
+ * The ASystemFontIterator_open method will give you an iterator which can iterate all system
+ * installed font files as shown in the following example.
+ *
+ * <code>
+ *   ASystemFontIterator* iterator = ASystemFontIterator_open();
+ *   ASystemFont* font = NULL;
+ *
+ *   while ((font = ASystemFontIterator_next(iterator)) != nullptr) {
+ *       // Look if the font is your desired one.
+ *       if (ASystemFont_getWeight(font) == 400 && !ASystemFont_isItalic(font)
+ *           && ASystemFont_getLocale(font) == NULL) {
+ *           break;
+ *       }
+ *       ASystemFont_close(font);
+ *   }
+ *   ASystemFontIterator_close(iterator);
+ *
+ *   int fd = open(ASystemFont_getFontFilePath(font), O_RDONLY);
+ *   int collectionIndex = ASystemFont_getCollectionINdex(font);
+ *   std::vector<std::pair<uint32_t, float>> variationSettings;
+ *   for (size_t i = 0; i < ASystemFont_getAxisCount(font); ++i) {
+ *       variationSettings.push_back(std::make_pair(
+ *           ASystemFont_getAxisTag(font, i),
+ *           ASystemFont_getAxisValue(font, i)));
+ *   }
+ *   ASystemFont_close(font);
+ *
+ *   // Use this font for your text rendering engine.
+ *
+ * </code>
+ *
+ * Available since API level 29.
+ */
+
+#ifndef ANDROID_SYSTEM_FONTS_H
+#define ANDROID_SYSTEM_FONTS_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <sys/cdefs.h>
+
+/******************************************************************
+ *
+ * IMPORTANT NOTICE:
+ *
+ *   This file is part of Android's set of stable system headers
+ *   exposed by the Android NDK (Native Development Kit).
+ *
+ *   Third-party source AND binary code relies on the definitions
+ *   here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES.
+ *
+ *   - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES)
+ *   - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS
+ *   - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY
+ *   - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES
+ */
+
+__BEGIN_DECLS
+
+#if __ANDROID_API__ >= 29
+
+enum {
+    /** The minimum value fot the font weight value. */
+    ASYSTEM_FONT_WEIGHT_MIN = 0,
+
+    /** A font weight value for the thin weight. */
+    ASYSTEM_FONT_WEIGHT_THIN = 100,
+
+    /** A font weight value for the extra-light weight. */
+    ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT = 200,
+
+    /** A font weight value for the light weight. */
+    ASYSTEM_FONT_WEIGHT_LIGHT = 300,
+
+    /** A font weight value for the normal weight. */
+    ASYSTEM_FONT_WEIGHT_NORMAL = 400,
+
+    /** A font weight value for the medium weight. */
+    ASYSTEM_FONT_WEIGHT_MEDIUM = 500,
+
+    /** A font weight value for the semi-bold weight. */
+    ASYSTEM_FONT_WEIGHT_SEMI_BOLD = 600,
+
+    /** A font weight value for the bold weight. */
+    ASYSTEM_FONT_WEIGHT_BOLD = 700,
+
+    /** A font weight value for the extra-bold weight. */
+    ASYSTEM_FONT_WEIGHT_EXTRA_BOLD = 800,
+
+    /** A font weight value for the black weight. */
+    ASYSTEM_FONT_WEIGHT_BLACK = 900,
+
+    /** The maximum value for the font weight value. */
+    ASYSTEM_FONT_WEIGHT_MAX = 1000
+};
+
+/**
+ * ASystemFontIterator provides access to the system font configuration.
+ *
+ * ASystemFontIterator is an iterator for all available system font settings.
+ * This iterator is not a thread-safe object. Do not pass this iterator to other threads.
+ */
+struct ASystemFontIterator;
+
+/**
+ * ASystemFont provides information of the single system font configuration.
+ */
+struct ASystemFont;
+
+/**
+ * Create a system font iterator.
+ *
+ * Use ASystemFont_close() to close the iterator.
+ *
+ * \return a pointer for a newly allocated iterator, nullptr on failure.
+ */
+ASystemFontIterator* _Nullable ASystemFontIterator_open() __INTRODUCED_IN(29);
+
+/**
+ * Close an opened system font iterator, freeing any related resources.
+ *
+ * \param a pointer of an iterator for the system fonts. Do nothing if NULL is passed.
+ */
+void ASystemFontIterator_close(ASystemFontIterator* _Nullable iterator) __INTRODUCED_IN(29);
+
+/**
+ * Move to the next system font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return true if more system fonts are available, otherwise false.
+ */
+ASystemFont* _Nullable ASystemFontIterator_next(ASystemFontIterator* _Nonnull iterator) __INTRODUCED_IN(29);
+
+/**
+ * Close an ASystemFont returned by ASystemFontIterator_next.
+ *
+ * \param font a font returned by ASystemFontIterator_next. Do nothing if NULL is passed.
+ */
+void ASystemFont_close(ASystemFont* _Nullable font) __INTRODUCED_IN(29);
+
+
+/**
+ * Return an absolute path to the current font file.
+ *
+ * Here is a list of font formats returned by this method:
+ * <ul>
+ *   <li>OpenType</li>
+ *   <li>OpenType Font Collection</li>
+ *   <li>TrueType</li>
+ *   <li>TrueType Collection</li>
+ * </ul>
+ * The file extension could be one of *.otf, *.ttf, *.otc or *.ttc.
+ *
+ * The font file returned is guaranteed to be opend with O_RDONLY.
+ * Note that the returned pointer is valid until ASystemFont_close() is called for the given font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a string of the font file path.
+ */
+const char* _Nonnull ASystemFont_getFontFilePath(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a weight value associated with the current font.
+ *
+ * The weight values are positive and less than or equal to 1000.
+ * Here are pairs of the common names and their values.
+ * <p>
+ *  <table>
+ *  <thead>
+ *  <tr>
+ *  <th align="center">Value</th>
+ *  <th align="center">Name</th>
+ *  <th align="center">NDK Definition</th>
+ *  </tr>
+ *  </thead>
+ *  <tbody>
+ *  <tr>
+ *  <td align="center">100</td>
+ *  <td align="center">Thin</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_THIN}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">200</td>
+ *  <td align="center">Extra Light (Ultra Light)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_LIGHT}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">300</td>
+ *  <td align="center">Light</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_LIGHT}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">400</td>
+ *  <td align="center">Normal (Regular)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_NORMAL}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">500</td>
+ *  <td align="center">Medium</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_MEDIUM}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">600</td>
+ *  <td align="center">Semi Bold (Demi Bold)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_SEMI_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">700</td>
+ *  <td align="center">Bold</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">800</td>
+ *  <td align="center">Extra Bold (Ultra Bold)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_EXTRA_BOLD}</td>
+ *  </tr>
+ *  <tr>
+ *  <td align="center">900</td>
+ *  <td align="center">Black (Heavy)</td>
+ *  <td align="center">{@link ASYSTEM_FONT_WEIGHT_BLACK}</td>
+ *  </tr>
+ *  </tbody>
+ * </p>
+ * Note that the weight value may fall in between above values, e.g. 250 weight.
+ *
+ * For more information about font weight, read [OpenType usWeightClass](https://docs.microsoft.com/en-us/typography/opentype/spec/os2#usweightclass)
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a positive integer less than or equal to {@link ASYSTEM_FONT_MAX_WEIGHT} is returned.
+ */
+uint16_t ASystemFont_getWeight(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return true if the current font is italic, otherwise returns false.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return true if italic, otherwise false.
+ */
+bool ASystemFont_isItalic(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a IETF BCP47 compliant language tag associated with the current font.
+ *
+ * For information about IETF BCP47, read [Locale.forLanguageTag(java.lang.String)](https://developer.android.com/reference/java/util/Locale.html#forLanguageTag(java.lang.String)")
+ *
+ * Note that the returned pointer is valid until ASystemFont_close() is called.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a IETF BCP47 compliant langauge tag or nullptr if not available.
+ */
+const char* _Nullable ASystemFont_getLocale(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a font collection index value associated with the current font.
+ *
+ * In case the target font file is a font collection (e.g. .ttc or .otc), this
+ * returns a non-negative value as an font offset in the collection. This
+ * always returns 0 if the target font file is a regular font.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a font collection index.
+ */
+size_t ASystemFont_getCollectionIndex(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+/**
+ * Return a count of font variation settings associated with the current font
+ *
+ * The font variation settings are provided as multiple tag-values pairs.
+ *
+ * For example, bold italic font may have following font variation settings:
+ *     'wght' 700, 'slnt' -12
+ * In this case, ASystemFont_getAxisCount returns 2 and ASystemFont_getAxisTag
+ * and ASystemFont_getAxisValue will return following values.
+ * <code>
+ *     ASystemFont* font = ASystemFontIterator_next(ite);
+ *
+ *     // Returns the number of axes
+ *     ASystemFont_getAxisCount(font);  // Returns 2
+ *
+ *     // Returns the tag-value pair for the first axis.
+ *     ASystemFont_getAxisTag(font, 0);  // Returns 'wght'(0x77676874)
+ *     ASystemFont_getAxisValue(font, 0);  // Returns 700.0
+ *
+ *     // Returns the tag-value pair for the second axis.
+ *     ASystemFont_getAxisTag(font, 1);  // Returns 'slnt'(0x736c6e74)
+ *     ASystemFont_getAxisValue(font, 1);  // Returns -12.0
+ * </code>
+ *
+ * For more information about font variation settings, read [Font Variations Table](https://docs.microsoft.com/en-us/typography/opentype/spec/fvar)
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \return a number of font variation settings.
+ */
+size_t ASystemFont_getAxisCount(const ASystemFont* _Nonnull font) __INTRODUCED_IN(29);
+
+
+/**
+ * Return an OpenType axis tag associated with the current font.
+ *
+ * See ASystemFont_getAxisCount for more details.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \param an index to the font variation settings. Passing value larger than or
+ *        equal to {@link ASystemFont_getAxisCount} is not allowed.
+ * \return an OpenType axis tag value for the given font variation setting.
+ */
+uint32_t ASystemFont_getAxisTag(const ASystemFont* _Nonnull font, uint32_t axisIndex)
+      __INTRODUCED_IN(29);
+
+/**
+ * Return an OpenType axis value associated with the current font.
+ *
+ * See ASystemFont_getAxisCount for more details.
+ *
+ * \param iterator an iterator for the system fonts. Passing NULL is not allowed.
+ * \param an index to the font variation settings. Passing value larger than or
+ *         equal to {@link ASYstemFont_getAxisCount} is not allwed.
+ * \return a float value for the given font variation setting.
+ */
+float ASystemFont_getAxisValue(const ASystemFont* _Nonnull font, uint32_t axisIndex)
+      __INTRODUCED_IN(29);
+
+#endif // __ANDROID_API__ >= 29
+
+__END_DECLS
+
+#endif // ANDROID_SYSTEM_FONTS_H
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 318070a..3f0dad0 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -151,11 +151,31 @@
 
     typedef void (*object_cleanup_func)(const void* id, void* obj, void* cleanupCookie);
 
+    /**
+     * This object is attached for the lifetime of this binder object. When
+     * this binder object is destructed, the cleanup function of all attached
+     * objects are invoked with their respective objectID, object, and
+     * cleanupCookie. Access to these APIs can be made from multiple threads,
+     * but calls from different threads are allowed to be interleaved.
+     */
     virtual void            attachObject(   const void* objectID,
                                             void* object,
                                             void* cleanupCookie,
                                             object_cleanup_func func) = 0;
+    /**
+     * Returns object attached with attachObject.
+     */
     virtual void*           findObject(const void* objectID) const = 0;
+    /**
+     * WARNING: this API does not call the cleanup function for legacy reasons.
+     * It also does not return void* for legacy reasons. If you need to detach
+     * an object and destroy it, there are two options:
+     * - if you can, don't call detachObject and instead wait for the destructor
+     *   to clean it up.
+     * - manually retrieve and destruct the object (if multiple of your threads
+     *   are accessing these APIs, you must guarantee that attachObject isn't
+     *   called after findObject and before detachObject is called).
+     */
     virtual void            detachObject(const void* objectID) = 0;
 
     virtual BBinder*        localBinder();
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index 76d5a73..e5c68b5 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -24,10 +24,10 @@
     ],
 
     srcs: [
-        "ABinderProcess.cpp",
-        "AIBinder.cpp",
-        "AParcel.cpp",
-        "AServiceManager.cpp",
+        "ibinder.cpp",
+        "parcel.cpp",
+        "process.cpp",
+        "service_manager.cpp",
     ],
 
     shared_libs: [
diff --git a/libs/binder/ndk/AIBinder.cpp b/libs/binder/ndk/ibinder.cpp
similarity index 67%
rename from libs/binder/ndk/AIBinder.cpp
rename to libs/binder/ndk/ibinder.cpp
index 2219f8e..8a1ec05 100644
--- a/libs/binder/ndk/AIBinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -15,13 +15,15 @@
  */
 
 #include <android/binder_ibinder.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <android/binder_status.h>
-#include "AParcel_internal.h"
+#include "parcel_internal.h"
 
 #include <android-base/logging.h>
 
+using DeathRecipient = ::android::IBinder::DeathRecipient;
+
 using ::android::IBinder;
 using ::android::Parcel;
 using ::android::sp;
@@ -32,10 +34,10 @@
 
 static const void* kId = "ABBinder";
 static void* kValue = static_cast<void*>(new bool{true});
-void cleanId(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
+void clean(const void* /*id*/, void* /*obj*/, void* /*cookie*/){/* do nothing */};
 
 static void attach(const sp<IBinder>& binder) {
-    binder->attachObject(kId, kValue, nullptr /*cookie*/, cleanId);
+    binder->attachObject(kId, kValue, nullptr /*cookie*/, clean);
 }
 static bool has(const sp<IBinder>& binder) {
     return binder != nullptr && binder->findObject(kId) == kValue;
@@ -43,6 +45,21 @@
 
 } // namespace ABBinderTag
 
+namespace ABpBinderTag {
+
+static std::mutex gLock;
+static const void* kId = "ABpBinder";
+struct Value {
+    wp<ABpBinder> binder;
+};
+void clean(const void* id, void* obj, void* cookie) {
+    CHECK(id == kId) << id << " " << obj << " " << cookie;
+
+    delete static_cast<Value*>(obj);
+};
+
+} // namespace ABpBinderTag
+
 AIBinder::AIBinder(const AIBinder_Class* clazz) : mClazz(clazz) {}
 AIBinder::~AIBinder() {}
 
@@ -121,14 +138,51 @@
 }
 ABpBinder::~ABpBinder() {}
 
-sp<AIBinder> ABpBinder::fromBinder(const ::android::sp<::android::IBinder>& binder) {
+void ABpBinder::onLastStrongRef(const void* id) {
+    {
+        std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
+        // Since ABpBinder is OBJECT_LIFETIME_WEAK, we must remove this weak reference in order for
+        // the ABpBinder to be deleted. Since a strong reference to this ABpBinder object should no
+        // longer be able to exist at the time of this method call, there is no longer a need to
+        // recover it.
+
+        ABpBinderTag::Value* value =
+                static_cast<ABpBinderTag::Value*>(remote()->findObject(ABpBinderTag::kId));
+        if (value != nullptr) {
+            value->binder = nullptr;
+        }
+    }
+
+    BpRefBase::onLastStrongRef(id);
+}
+
+sp<AIBinder> ABpBinder::lookupOrCreateFromBinder(const ::android::sp<::android::IBinder>& binder) {
     if (binder == nullptr) {
         return nullptr;
     }
     if (ABBinderTag::has(binder)) {
         return static_cast<ABBinder*>(binder.get());
     }
-    return new ABpBinder(binder);
+
+    // The following code ensures that for a given binder object (remote or local), if it is not an
+    // ABBinder then at most one ABpBinder object exists in a given process representing it.
+    std::lock_guard<std::mutex> lock(ABpBinderTag::gLock);
+
+    ABpBinderTag::Value* value =
+            static_cast<ABpBinderTag::Value*>(binder->findObject(ABpBinderTag::kId));
+    if (value == nullptr) {
+        value = new ABpBinderTag::Value;
+        binder->attachObject(ABpBinderTag::kId, static_cast<void*>(value), nullptr /*cookie*/,
+                             ABpBinderTag::clean);
+    }
+
+    sp<ABpBinder> ret = value->binder.promote();
+    if (ret == nullptr) {
+        ret = new ABpBinder(binder);
+        value->binder = ret;
+    }
+
+    return ret;
 }
 
 struct AIBinder_Weak {
@@ -179,6 +233,63 @@
     return new AIBinder_Class(interfaceDescriptor, onCreate, onDestroy, onTransact);
 }
 
+void AIBinder_DeathRecipient::TransferDeathRecipient::binderDied(const wp<IBinder>& who) {
+    CHECK(who == mWho);
+
+    mOnDied(mCookie);
+    mWho = nullptr;
+}
+
+AIBinder_DeathRecipient::AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied)
+      : mOnDied(onDied) {
+    CHECK(onDied != nullptr);
+}
+
+binder_status_t AIBinder_DeathRecipient::linkToDeath(AIBinder* binder, void* cookie) {
+    CHECK(binder != nullptr);
+
+    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
+
+    sp<TransferDeathRecipient> recipient =
+            new TransferDeathRecipient(binder->getBinder(), cookie, mOnDied);
+
+    binder_status_t status = binder->getBinder()->linkToDeath(recipient, cookie, 0 /*flags*/);
+    if (status != EX_NONE) {
+        return status;
+    }
+
+    mDeathRecipients.push_back(recipient);
+    return EX_NONE;
+}
+
+binder_status_t AIBinder_DeathRecipient::unlinkToDeath(AIBinder* binder, void* cookie) {
+    CHECK(binder != nullptr);
+
+    std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
+
+    for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) {
+        sp<TransferDeathRecipient> recipient = *it;
+
+        if (recipient->getCookie() == cookie &&
+
+            recipient->getWho() == binder->getBinder()) {
+            mDeathRecipients.erase(it.base() - 1);
+
+            binder_status_t status =
+                    binder->getBinder()->unlinkToDeath(recipient, cookie, 0 /*flags*/);
+            if (status != EX_NONE) {
+                LOG(ERROR) << __func__
+                           << ": removed reference to death recipient but unlink failed.";
+            }
+            return status;
+        }
+    }
+
+    return -ENOENT;
+}
+
+// start of C-API methods
+
 AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args) {
     if (clazz == nullptr) {
         LOG(ERROR) << __func__ << ": Must provide class to construct local binder.";
@@ -218,6 +329,26 @@
     return binder->getBinder()->pingBinder();
 }
 
+binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                     void* cookie) {
+    if (binder == nullptr || recipient == nullptr) {
+        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        return EX_NULL_POINTER;
+    }
+
+    return recipient->linkToDeath(binder, cookie);
+}
+
+binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                       void* cookie) {
+    if (binder == nullptr || recipient == nullptr) {
+        LOG(ERROR) << __func__ << ": Must provide binder and recipient.";
+        return EX_NULL_POINTER;
+    }
+
+    return recipient->unlinkToDeath(binder, cookie);
+}
+
 void AIBinder_incStrong(AIBinder* binder) {
     if (binder == nullptr) {
         LOG(ERROR) << __func__ << ": on null binder";
@@ -347,3 +478,21 @@
 
     return parcelStatus;
 }
+
+AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
+        AIBinder_DeathRecipient_onBinderDied onBinderDied) {
+    if (onBinderDied == nullptr) {
+        LOG(ERROR) << __func__ << ": requires non-null onBinderDied parameter.";
+        return nullptr;
+    }
+    return new AIBinder_DeathRecipient(onBinderDied);
+}
+
+void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient** recipient) {
+    if (recipient == nullptr) {
+        return;
+    }
+
+    delete *recipient;
+    *recipient = nullptr;
+}
diff --git a/libs/binder/ndk/AIBinder_internal.h b/libs/binder/ndk/ibinder_internal.h
similarity index 65%
rename from libs/binder/ndk/AIBinder_internal.h
rename to libs/binder/ndk/ibinder_internal.h
index 23949bb..fcf1b0b 100644
--- a/libs/binder/ndk/AIBinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -17,9 +17,11 @@
 #pragma once
 
 #include <android/binder_ibinder.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <atomic>
+#include <mutex>
+#include <vector>
 
 #include <binder/Binder.h>
 #include <binder/IBinder.h>
@@ -79,13 +81,18 @@
     void* mUserData;
 };
 
-// This binder object may be remote or local (even though it is 'Bp'). It is not yet associated with
-// a class.
+// This binder object may be remote or local (even though it is 'Bp'). The implication if it is
+// local is that it is an IBinder object created outside of the domain of libbinder_ndk.
 struct ABpBinder : public AIBinder, public ::android::BpRefBase {
-    static ::android::sp<AIBinder> fromBinder(const ::android::sp<::android::IBinder>& binder);
+    // Looks up to see if this object has or is an existing ABBinder or ABpBinder object, otherwise
+    // it creates an ABpBinder object.
+    static ::android::sp<AIBinder> lookupOrCreateFromBinder(
+            const ::android::sp<::android::IBinder>& binder);
 
     virtual ~ABpBinder();
 
+    void onLastStrongRef(const void* id) override;
+
     ::android::sp<::android::IBinder> getBinder() override { return remote(); }
     ABpBinder* asABpBinder() override { return this; }
 
@@ -108,3 +115,38 @@
     // one.
     const ::android::String16 mInterfaceDescriptor;
 };
+
+// Ownership is like this (when linked to death):
+//
+//   AIBinder_DeathRecipient -sp-> TransferDeathRecipient <-wp-> IBinder
+//
+// When the AIBinder_DeathRecipient is dropped, so are the actual underlying death recipients. When
+// the IBinder dies, only a wp to it is kept.
+struct AIBinder_DeathRecipient {
+    // One of these is created for every linkToDeath. This is to be able to recover data when a
+    // binderDied receipt only gives us information about the IBinder.
+    struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
+        TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
+                               const AIBinder_DeathRecipient_onBinderDied& onDied)
+              : mWho(who), mCookie(cookie), mOnDied(onDied) {}
+
+        void binderDied(const ::android::wp<::android::IBinder>& who) override;
+
+        const ::android::wp<::android::IBinder>& getWho() { return mWho; }
+        void* getCookie() { return mCookie; }
+
+    private:
+        ::android::wp<::android::IBinder> mWho;
+        void* mCookie;
+        const AIBinder_DeathRecipient_onBinderDied& mOnDied;
+    };
+
+    AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
+    binder_status_t linkToDeath(AIBinder* binder, void* cookie);
+    binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);
+
+private:
+    std::mutex mDeathRecipientsMutex;
+    std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
+    AIBinder_DeathRecipient_onBinderDied mOnDied;
+};
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index aa29437..7dca5a4 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -14,6 +14,16 @@
  * limitations under the License.
  */
 
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_ibinder.h
+ * @brief Object which can receive transactions and be sent across processes.
+ */
+
 #pragma once
 
 #include <stdint.h>
@@ -84,6 +94,16 @@
  * implementation (usually a callback) to transfer all ownership to a remote process and
  * automatically be deleted when the remote process is done with it or dies. Other memory models are
  * possible, but this is the standard one.
+ *
+ * If the process containing an AIBinder dies, it is possible to be holding a strong reference to
+ * an object which does not exist. In this case, transactions to this binder will return
+ * EX_DEAD_OBJECT. See also AIBinder_linkToDeath, AIBinder_unlinkToDeath, and AIBinder_isAlive.
+ *
+ * Once an AIBinder is created, anywhere it is passed (remotely or locally), there is a 1-1
+ * correspondence between the address of an AIBinder and the object it represents. This means that
+ * when two AIBinder pointers point to the same address, they represent the same object (whether
+ * that object is local or remote). This correspondance can be broken accidentally if AIBinder_new
+ * is erronesouly called to create the same object multiple times.
  */
 struct AIBinder;
 typedef struct AIBinder AIBinder;
@@ -97,6 +117,12 @@
 typedef struct AIBinder_Weak AIBinder_Weak;
 
 /**
+ * Represents a handle on a death notification. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ */
+struct AIBinder_DeathRecipient;
+typedef struct AIBinder_DeathRecipient AIBinder_DeathRecipient;
+
+/**
  * This is called whenever a new AIBinder object is needed of a specific class.
  *
  * These arguments are passed from AIBinder_new. The return value is stored and can be retrieved
@@ -138,6 +164,14 @@
  *
  * When this is called, the refcount is implicitly 1. So, calling decStrong exactly one time is
  * required to delete this object.
+ *
+ * Once an AIBinder object is created using this API, re-creating that AIBinder for the same
+ * instance of the same class will break pointer equality for that specific AIBinder object. For
+ * instance, if someone erroneously created two AIBinder instances representing the same callback
+ * object and passed one to a hypothetical addCallback function and then later another one to a
+ * hypothetical removeCallback function, the remote process would have no way to determine that
+ * these two objects are actually equal using the AIBinder pointer alone (which they should be able
+ * to do). Also see the suggested memory ownership model suggested above.
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_new(const AIBinder_Class* clazz, void* args);
 
@@ -163,6 +197,26 @@
 binder_status_t AIBinder_ping(AIBinder* binder);
 
 /**
+ * Registers for notifications that the associated binder is dead. The same death recipient may be
+ * associated with multiple different binders. If the binder is local, then no death recipient will
+ * be given (since if the local process dies, then no recipient will exist to recieve a
+ * transaction). The cookie is passed to recipient in the case that this binder dies and can be
+ * null. The exact cookie must also be used to unlink this transaction (see AIBinder_linkToDeath).
+ * This function may return a binder transaction failure. The cookie can be used both for
+ * identification and holding user data.
+ */
+binder_status_t AIBinder_linkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                     void* cookie);
+
+/**
+ * Stops registration for the associated binder dying. Does not delete the recipient. This function
+ * may return a binder transaction failure and in case the death recipient cannot be found, it
+ * returns -ENOENT.
+ */
+binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
+                                       void* cookie);
+
+/**
  * This can only be called if a strong reference to this object already exists in process.
  */
 void AIBinder_incStrong(AIBinder* binder);
@@ -254,4 +308,23 @@
  */
 __attribute__((warn_unused_result)) AIBinder* AIBinder_Weak_promote(AIBinder_Weak* weakBinder);
 
+/**
+ * This function is executed on death receipt. See AIBinder_linkToDeath/AIBinder_unlinkToDeath.
+ */
+typedef void (*AIBinder_DeathRecipient_onBinderDied)(void* cookie);
+
+/**
+ * Creates a new binder death recipient. This can be attached to multiple different binder objects.
+ */
+__attribute__((warn_unused_result)) AIBinder_DeathRecipient* AIBinder_DeathRecipient_new(
+        AIBinder_DeathRecipient_onBinderDied onBinderDied);
+
+/**
+ * Deletes a binder death recipient. It is not necessary to call AIBinder_unlinkToDeath before
+ * calling this as these will all be automatically unlinked.
+ */
+void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient** recipient);
+
 __END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_parcel.h b/libs/binder/ndk/include_ndk/android/binder_parcel.h
index 19925f7..e871ed1 100644
--- a/libs/binder/ndk/include_ndk/android/binder_parcel.h
+++ b/libs/binder/ndk/include_ndk/android/binder_parcel.h
@@ -14,6 +14,16 @@
  * limitations under the License.
  */
 
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcel.h
+ * @brief A collection of data that can be sent as a single packet.
+ */
+
 #pragma once
 
 #include <sys/cdefs.h>
@@ -150,3 +160,5 @@
 // @END
 
 __END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/include_ndk/android/binder_status.h b/libs/binder/ndk/include_ndk/android/binder_status.h
index d414c99..e97e181 100644
--- a/libs/binder/ndk/include_ndk/android/binder_status.h
+++ b/libs/binder/ndk/include_ndk/android/binder_status.h
@@ -14,6 +14,15 @@
  * limitations under the License.
  */
 
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_status.h
+ */
+
 #pragma once
 
 #include <stdint.h>
@@ -54,3 +63,5 @@
 typedef int32_t binder_status_t;
 
 __END_DECLS
+
+/** @} */
diff --git a/libs/binder/ndk/AParcel.cpp b/libs/binder/ndk/parcel.cpp
similarity index 91%
rename from libs/binder/ndk/AParcel.cpp
rename to libs/binder/ndk/parcel.cpp
index 93384d6..ccdfc7b 100644
--- a/libs/binder/ndk/AParcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -15,9 +15,9 @@
  */
 
 #include <android/binder_parcel.h>
-#include "AParcel_internal.h"
+#include "parcel_internal.h"
 
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <binder/Parcel.h>
 
@@ -35,7 +35,8 @@
 }
 
 binder_status_t AParcel_writeStrongBinder(AParcel* parcel, AIBinder* binder) {
-    return (*parcel)->writeStrongBinder(binder->getBinder());
+    sp<IBinder> writeBinder = binder != nullptr ? binder->getBinder() : nullptr;
+    return (*parcel)->writeStrongBinder(writeBinder);
 }
 binder_status_t AParcel_readStrongBinder(const AParcel* parcel, AIBinder** binder) {
     sp<IBinder> readBinder = nullptr;
@@ -43,7 +44,7 @@
     if (status != EX_NONE) {
         return status;
     }
-    sp<AIBinder> ret = ABpBinder::fromBinder(readBinder);
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder);
     AIBinder_incStrong(ret.get());
     *binder = ret.get();
     return status;
@@ -54,7 +55,7 @@
     if (status != EX_NONE) {
         return status;
     }
-    sp<AIBinder> ret = ABpBinder::fromBinder(readBinder);
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(readBinder);
     AIBinder_incStrong(ret.get());
     *binder = ret.get();
     return status;
diff --git a/libs/binder/ndk/AParcel_internal.h b/libs/binder/ndk/parcel_internal.h
similarity index 98%
rename from libs/binder/ndk/AParcel_internal.h
rename to libs/binder/ndk/parcel_internal.h
index 9f30a2f..b6a9110 100644
--- a/libs/binder/ndk/AParcel_internal.h
+++ b/libs/binder/ndk/parcel_internal.h
@@ -21,7 +21,7 @@
 #include <sys/cdefs.h>
 
 #include <binder/Parcel.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 struct AParcel {
     const ::android::Parcel* operator->() const { return mParcel; }
diff --git a/libs/binder/ndk/ABinderProcess.cpp b/libs/binder/ndk/process.cpp
similarity index 100%
rename from libs/binder/ndk/ABinderProcess.cpp
rename to libs/binder/ndk/process.cpp
diff --git a/libs/binder/ndk/scripts/gen_parcel_helper.py b/libs/binder/ndk/scripts/gen_parcel_helper.py
index 5c0b936..794afe2 100755
--- a/libs/binder/ndk/scripts/gen_parcel_helper.py
+++ b/libs/binder/ndk/scripts/gen_parcel_helper.py
@@ -81,7 +81,7 @@
         source += "}\n\n"
 
     replaceFileTags(ROOT + "include_ndk/android/binder_parcel.h", header)
-    replaceFileTags(ROOT + "AParcel.cpp", source)
+    replaceFileTags(ROOT + "parcel.cpp", source)
 
     print("Updating DONE.")
 
diff --git a/libs/binder/ndk/AServiceManager.cpp b/libs/binder/ndk/service_manager.cpp
similarity index 93%
rename from libs/binder/ndk/AServiceManager.cpp
rename to libs/binder/ndk/service_manager.cpp
index 3979945..5bc69b0 100644
--- a/libs/binder/ndk/AServiceManager.cpp
+++ b/libs/binder/ndk/service_manager.cpp
@@ -15,7 +15,7 @@
  */
 
 #include <android/binder_manager.h>
-#include "AIBinder_internal.h"
+#include "ibinder_internal.h"
 
 #include <binder/IServiceManager.h>
 
@@ -41,7 +41,7 @@
     sp<IServiceManager> sm = defaultServiceManager();
     sp<IBinder> binder = sm->getService(String16(instance));
 
-    sp<AIBinder> ret = ABpBinder::fromBinder(binder);
+    sp<AIBinder> ret = ABpBinder::lookupOrCreateFromBinder(binder);
     AIBinder_incStrong(ret.get());
     return ret.get();
 }
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index 967789f..b8518d7 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -16,6 +16,7 @@
 
 #include <android-base/logging.h>
 #include <android/binder_manager.h>
+#include <android/binder_process.h>
 #include <gtest/gtest.h>
 #include <iface/iface.h>
 
@@ -45,6 +46,28 @@
     AIBinder_decStrong(binder);
 }
 
+void OnBinderDeath(void* cookie) {
+    LOG(ERROR) << "BINDER DIED. COOKIE: " << cookie;
+}
+
+TEST(NdkBinder, LinkToDeath) {
+    ABinderProcess_setThreadPoolMaxThreadCount(1); // to recieve death notifications
+    ABinderProcess_startThreadPool();
+
+    AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binder);
+
+    AIBinder_DeathRecipient* recipient = AIBinder_DeathRecipient_new(OnBinderDeath);
+    ASSERT_NE(nullptr, recipient);
+
+    EXPECT_EQ(EX_NONE, AIBinder_linkToDeath(binder, recipient, nullptr));
+    EXPECT_EQ(EX_NONE, AIBinder_unlinkToDeath(binder, recipient, nullptr));
+    EXPECT_EQ(-ENOENT, AIBinder_unlinkToDeath(binder, recipient, nullptr));
+
+    AIBinder_DeathRecipient_delete(&recipient);
+    AIBinder_decStrong(binder);
+}
+
 class MyTestFoo : public IFoo {
     int32_t doubleNumber(int32_t in) override {
         LOG(INFO) << "doubleNumber " << in;
@@ -64,6 +87,34 @@
     EXPECT_EQ(2, getFoo->doubleNumber(1));
 }
 
+TEST(NdkBinder, EqualityOfRemoteBinderPointer) {
+    AIBinder* binderA = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binderA);
+
+    AIBinder* binderB = AServiceManager_getService(kExistingNonNdkService);
+    ASSERT_NE(nullptr, binderB);
+
+    EXPECT_EQ(binderA, binderB);
+
+    AIBinder_decStrong(binderA);
+    AIBinder_decStrong(binderB);
+}
+
+TEST(NdkBinder, ABpBinderRefCount) {
+    AIBinder* binder = AServiceManager_getService(kExistingNonNdkService);
+    AIBinder_Weak* wBinder = AIBinder_Weak_new(binder);
+
+    ASSERT_NE(nullptr, binder);
+    EXPECT_EQ(1, AIBinder_debugGetRefCount(binder));
+
+    AIBinder_decStrong(binder);
+
+    // assert because would need to decStrong if non-null and we shouldn't need to add a no-op here
+    ASSERT_NE(nullptr, AIBinder_Weak_promote(wBinder));
+
+    AIBinder_Weak_delete(&wBinder);
+}
+
 TEST(NdkBinder, AddServiceMultipleTimes) {
     static const char* kInstanceName1 = "test-multi-1";
     static const char* kInstanceName2 = "test-multi-2";
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index deb8ea8..5a8d8db 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "LayerState"
+
 #include <utils/Errors.h>
 #include <binder/Parcel.h>
 #include <gui/ISurfaceComposerClient.h>
@@ -313,8 +315,10 @@
         sidebandStream = other.sidebandStream;
     }
 
-    if (other.what != what) {
-        ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating?");
+    if ((other.what & what) != other.what) {
+        ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
+              "other.what=0x%X what=0x%X",
+              other.what, what);
     }
 }
 
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index 2ab5b65..37b9a03 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -593,7 +593,7 @@
 
   LocalHandle fence;
 
-  EXPECT_EQ(0, p->Post<void>(LocalHandle()));
+  EXPECT_EQ(0, p->Post(LocalHandle()));
   EXPECT_EQ(0, c->Acquire(&fence));
 }
 
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index b71f5dc..0b2666a 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -212,11 +212,10 @@
   int Post(const LocalHandle& ready_fence, const void* meta,
            size_t user_metadata_size);
 
-  template <typename Meta,
-            typename = typename std::enable_if<std::is_void<Meta>::value>::type>
   int Post(const LocalHandle& ready_fence) {
     return Post(ready_fence, nullptr, 0);
   }
+
   template <typename Meta, typename = typename std::enable_if<
                                !std::is_void<Meta>::value>::type>
   int Post(const LocalHandle& ready_fence, const Meta& meta) {
diff --git a/libs/vr/libpdx_default_transport/Android.bp b/libs/vr/libpdx_default_transport/Android.bp
index 74b8c8b..1176abf 100644
--- a/libs/vr/libpdx_default_transport/Android.bp
+++ b/libs/vr/libpdx_default_transport/Android.bp
@@ -40,6 +40,7 @@
         "liblog",
         "libutils",
         "libcrypto",
+        "libselinux",
     ],
 }
 
diff --git a/libs/vr/libpdx_uds/Android.bp b/libs/vr/libpdx_uds/Android.bp
index d640950..1d6eea2 100644
--- a/libs/vr/libpdx_uds/Android.bp
+++ b/libs/vr/libpdx_uds/Android.bp
@@ -26,8 +26,6 @@
     ],
     shared_libs: [
         "libbinder",
-    ],
-    whole_static_libs: [
         "libselinux",
     ],
 }
@@ -57,5 +55,6 @@
         "liblog",
         "libutils",
         "libbinder",
+        "libselinux",
     ],
 }
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 10974b4..4839bfb 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -433,6 +433,10 @@
     if (mFlinger->isLayerTripleBufferingDisabled()) {
         mProducer->setMaxDequeuedBufferCount(2);
     }
+
+    if (const auto display = mFlinger->getDefaultDisplayDevice()) {
+        updateTransformHint(display);
+    }
 }
 
 status_t BufferQueueLayer::setDefaultBufferProperties(uint32_t w, uint32_t h, PixelFormat format) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index d963ab6..6b56ca4 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -500,6 +500,8 @@
             validateChange(compositionInfo.compositionType,
                     changedTypes[&*hwcLayer]);
             compositionInfo.compositionType = changedTypes[&*hwcLayer];
+            compositionInfo.layer->mLayer->setCompositionType(displayId,
+                    compositionInfo.compositionType, false);
         }
 
         switch (compositionInfo.compositionType) {
@@ -520,6 +522,7 @@
                 layerRequests[&*hwcLayer] ==
                         HWC2::LayerRequest::ClearClientTarget) {
             compositionInfo.hwc.clearClientTarget = true;
+            compositionInfo.layer->mLayer->setClearClientTarget(displayId, true);
         } else {
             if (layerRequests.count(&*hwcLayer) != 0) {
                 LOG_DISPLAY_ERROR(displayId,
@@ -527,6 +530,7 @@
                                           .c_str());
             }
             compositionInfo.hwc.clearClientTarget = false;
+            compositionInfo.layer->mLayer->setClearClientTarget(displayId, false);
         }
     }
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a1e45b0..03b63bd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -680,6 +680,10 @@
     engine.drawMesh(getBE().mMesh);
 }
 
+void Layer::clearWithOpenGL(const RenderArea& renderArea) const {
+    clearWithOpenGL(renderArea, 0, 0, 0, 0);
+}
+
 void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool /*callIntoHwc*/) {
     if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("setCompositionType called without a valid HWC layer");
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9bd28b8..3845b22 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -503,6 +503,7 @@
     }
 
     // -----------------------------------------------------------------------
+    void clearWithOpenGL(const RenderArea& renderArea) const;
 
     inline const State& getDrawingState() const { return mDrawingState; }
     inline const State& getCurrentState() const { return mCurrentState; }
@@ -590,6 +591,9 @@
 
     friend class impl::SurfaceInterceptor;
 
+    // For unit tests
+    friend class TestableSurfaceFlinger;
+
     void commitTransaction(const State& stateToCommit);
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index f5150a7..2722b01 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -87,6 +87,9 @@
     friend class ColorLayer;
     friend class SurfaceFlinger;
 
+    // For unit tests
+    friend class TestableSurfaceFlinger;
+
     LayerBE(Layer* layer, std::string layerName);
     explicit LayerBE(const LayerBE& layer);
 
@@ -94,8 +97,8 @@
     void clear(renderengine::RenderEngine& renderEngine);
     renderengine::Mesh& getMesh() { return mMesh; }
 
-private:
     Layer*const mLayer;
+private:
     // The mesh used to draw the layer in GLES composition mode
     renderengine::Mesh mMesh;
 
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index bb85f4c..54e19c7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -39,7 +39,7 @@
 Scheduler::~Scheduler() = default;
 
 sp<Scheduler::ConnectionHandle> Scheduler::createConnection(
-        const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+        const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
         impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
     const int64_t id = sNextId++;
@@ -56,13 +56,15 @@
 }
 
 std::unique_ptr<EventThread> Scheduler::makeEventThread(
-        const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+        const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
         impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
         impl::EventThread::InterceptVSyncsCallback interceptCallback) {
+    const std::string sourceName = connectionName + "Source";
     std::unique_ptr<VSyncSource> eventThreadSource =
-            std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, connectionName);
+            std::make_unique<DispSyncSource>(dispSync, phaseOffsetNs, true, sourceName.c_str());
+    const std::string threadName = connectionName + "Thread";
     return std::make_unique<impl::EventThread>(std::move(eventThreadSource), resyncCallback,
-                                               interceptCallback, connectionName);
+                                               interceptCallback, threadName.c_str());
 }
 
 sp<IDisplayEventConnection> Scheduler::createDisplayEventConnection(
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 8efbff4..fcb46e6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -56,7 +56,7 @@
 
     /** Creates an EventThread connection. */
     sp<ConnectionHandle> createConnection(
-            const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+            const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
             impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
     sp<IDisplayEventConnection> createDisplayEventConnection(const sp<ConnectionHandle>& handle);
@@ -79,7 +79,7 @@
 
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
-            const char* connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
+            const std::string& connectionName, DispSync* dispSync, int64_t phaseOffsetNs,
             impl::EventThread::ResyncWithRateLimitCallback resyncCallback,
             impl::EventThread::InterceptVSyncsCallback interceptCallback);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9537ccc..f17710e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -3218,30 +3218,29 @@
     ALOGV("Rendering client layers");
     const ui::Transform& displayTransform = display->getTransform();
     bool firstLayer = true;
-    for (auto& compositionInfo : getBE().mCompositionInfo[displayId]) {
-        const Region bounds(display->bounds());
+    for (auto& layer : display->getVisibleLayersSortedByZ()) {
         const Region clip(bounds.intersect(
-                displayTransform.transform(compositionInfo.layer->mLayer->visibleRegion)));
-        ALOGV("Layer: %s", compositionInfo.layerName.c_str());
+                displayTransform.transform(layer->visibleRegion)));
+        ALOGV("Layer: %s", layer->getName().string());
+        ALOGV("  Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
         if (!clip.isEmpty()) {
-            switch (compositionInfo.compositionType) {
+            switch (layer->getCompositionType(displayId)) {
                 case HWC2::Composition::Cursor:
                 case HWC2::Composition::Device:
                 case HWC2::Composition::Sideband:
                 case HWC2::Composition::SolidColor: {
-                    const Layer::State& state(compositionInfo.layer->mLayer->getDrawingState());
-                    const bool opaque = compositionInfo.layer->mLayer->isOpaque(state) &&
-                                        compositionInfo.layer->mLayer->getAlpha() == 1.0f;
-                    if (compositionInfo.hwc.clearClientTarget && !firstLayer && opaque &&
-                            hasClientComposition) {
+                    const Layer::State& state(layer->getDrawingState());
+                    if (layer->getClearClientTarget(displayId) && !firstLayer &&
+                        layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
+                        hasClientComposition) {
                         // never clear the very first layer since we're
                         // guaranteed the FB is already cleared
-                        compositionInfo.layer->clear(getRenderEngine());
+                        layer->clearWithOpenGL(renderArea);
                     }
                     break;
                 }
                 case HWC2::Composition::Client: {
-                    compositionInfo.layer->mLayer->draw(renderArea, clip);
+                    layer->draw(renderArea, clip);
                     break;
                 }
                 default:
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index f1f0fbf..6fe52d3 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -1,4 +1,4 @@
-// Copyright (C) 2018 The Android Open Source Project
+// Copyright 2018 The Android Open Source Project
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -16,8 +16,15 @@
     name: "libsurfaceflinger_unittest",
     defaults: ["libsurfaceflinger_defaults"],
     test_suites: ["device-tests"],
+    sanitize: {
+        // Using the address sanitizer not only helps uncover issues in the code
+        // covered by the tests, but also covers some of the tricky injection of
+        // fakes the unit tests currently do.
+        address: true,
+    },
     srcs: [
         ":libsurfaceflinger_sources",
+        "CompositionTest.cpp",
         "DisplayIdentificationTest.cpp",
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
new file mode 100644
index 0000000..5aa6e27
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -0,0 +1,1275 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "CompositionTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <gui/IProducerListener.h>
+#include <log/log.h>
+#include <system/window.h>
+#include <utils/String8.h>
+
+#include "BufferQueueLayer.h"
+#include "ColorLayer.h"
+#include "Layer.h"
+
+#include "TestableSurfaceFlinger.h"
+#include "mock/DisplayHardware/MockComposer.h"
+#include "mock/DisplayHardware/MockDisplaySurface.h"
+#include "mock/MockDispSync.h"
+#include "mock/MockEventControlThread.h"
+#include "mock/MockEventThread.h"
+#include "mock/MockMessageQueue.h"
+#include "mock/RenderEngine/MockRenderEngine.h"
+
+namespace android {
+namespace {
+
+using testing::_;
+using testing::ByMove;
+using testing::DoAll;
+using testing::IsNull;
+using testing::Mock;
+using testing::NotNull;
+using testing::Ref;
+using testing::Return;
+using testing::ReturnRef;
+using testing::SetArgPointee;
+
+using android::Hwc2::Error;
+using android::Hwc2::IComposer;
+using android::Hwc2::IComposerClient;
+using android::Hwc2::Transform;
+
+using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector;
+using FakeDisplayDeviceInjector = TestableSurfaceFlinger::FakeDisplayDeviceInjector;
+
+constexpr hwc2_display_t HWC_DISPLAY = FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID;
+constexpr hwc2_layer_t HWC_LAYER = 5000;
+constexpr Transform DEFAULT_TRANSFORM = static_cast<Transform>(0);
+
+constexpr int DEFAULT_DISPLAY_WIDTH = 1920;
+constexpr int DEFAULT_DISPLAY_HEIGHT = 1024;
+
+constexpr int DEFAULT_CONFIG_ID = 0;
+constexpr int DEFAULT_TEXTURE_ID = 6000;
+constexpr int DEFAULT_LAYER_STACK = 7000;
+
+constexpr int DEFAULT_DISPLAY_MAX_LUMINANCE = 500;
+
+constexpr int DEFAULT_SIDEBAND_STREAM = 51;
+
+class CompositionTest : public testing::Test {
+public:
+    CompositionTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+
+        mFlinger.mutableEventControlThread().reset(mEventControlThread);
+        mFlinger.mutableEventThread().reset(mEventThread);
+        mFlinger.mutableEventQueue().reset(mMessageQueue);
+
+        mFlinger.mutablePrimaryDispSync().reset(mPrimaryDispSync);
+        EXPECT_CALL(*mPrimaryDispSync, computeNextRefresh(0)).WillRepeatedly(Return(0));
+        EXPECT_CALL(*mPrimaryDispSync, getPeriod())
+                .WillRepeatedly(Return(FakeHwcDisplayInjector::DEFAULT_REFRESH_RATE));
+
+        mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
+        setupComposer(0);
+    }
+
+    ~CompositionTest() {
+        const ::testing::TestInfo* const test_info =
+                ::testing::UnitTest::GetInstance()->current_test_info();
+        ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+    }
+
+    void setupComposer(int virtualDisplayCount) {
+        mComposer = new Hwc2::mock::Composer();
+        EXPECT_CALL(*mComposer, getCapabilities())
+                .WillOnce(Return(std::vector<IComposer::Capability>()));
+        EXPECT_CALL(*mComposer, getMaxVirtualDisplayCount()).WillOnce(Return(virtualDisplayCount));
+        mFlinger.setupComposer(std::unique_ptr<Hwc2::Composer>(mComposer));
+
+        Mock::VerifyAndClear(mComposer);
+    }
+
+    void setupForceGeometryDirty() {
+        // TODO: This requires the visible region and other related
+        // state to be set, and is problematic for BufferLayers since they are
+        // not visible without a buffer (and setting up a buffer looks like a
+        // pain)
+        // mFlinger.mutableVisibleRegionsDirty() = true;
+
+        mFlinger.mutableGeometryInvalid() = true;
+    }
+
+    template <typename Case>
+    void displayRefreshCompositionDirtyGeometry();
+
+    template <typename Case>
+    void displayRefreshCompositionDirtyFrame();
+
+    template <typename Case>
+    void captureScreenComposition();
+
+    std::unordered_set<HWC2::Capability> mDefaultCapabilities = {HWC2::Capability::SidebandStream};
+
+    TestableSurfaceFlinger mFlinger;
+    sp<DisplayDevice> mDisplay;
+    sp<DisplayDevice> mExternalDisplay;
+    sp<mock::DisplaySurface> mDisplaySurface = new mock::DisplaySurface();
+    renderengine::mock::Surface* mRenderSurface = new renderengine::mock::Surface();
+
+    mock::EventThread* mEventThread = new mock::EventThread();
+    mock::EventControlThread* mEventControlThread = new mock::EventControlThread();
+
+    Hwc2::mock::Composer* mComposer = nullptr;
+    renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
+    mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
+    mock::DispSync* mPrimaryDispSync = new mock::DispSync();
+    renderengine::mock::Image* mReImage = new renderengine::mock::Image();
+    renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
+
+    sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
+
+    sp<GraphicBuffer> mCaptureScreenBuffer;
+};
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyGeometry() {
+    setupForceGeometryDirty();
+    LayerCase::setupForDirtyGeometry(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+    mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+    LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::displayRefreshCompositionDirtyFrame() {
+    LayerCase::setupForDirtyFrame(this);
+
+    // --------------------------------------------------------------------
+    // Invocation
+
+    mFlinger.onMessageReceived(MessageQueue::INVALIDATE);
+    mFlinger.onMessageReceived(MessageQueue::REFRESH);
+
+    LayerCase::cleanup(this);
+}
+
+template <typename LayerCase>
+void CompositionTest::captureScreenComposition() {
+    LayerCase::setupForScreenCapture(this);
+
+    const Rect sourceCrop(0, 0, DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT);
+    constexpr int32_t minLayerZ = -1;
+    constexpr int32_t maxLayerZ = 1000;
+    constexpr bool useIdentityTransform = true;
+    constexpr bool forSystem = true;
+
+    DisplayRenderArea renderArea(mDisplay, sourceCrop, DEFAULT_DISPLAY_WIDTH,
+                                 DEFAULT_DISPLAY_HEIGHT, ui::Transform::ROT_0);
+
+    auto traverseLayers = [this](const LayerVector::Visitor& visitor) {
+        return mFlinger.traverseLayersInDisplay(mDisplay, minLayerZ, maxLayerZ, visitor);
+    };
+
+    // TODO: Eliminate expensive/real allocation if possible.
+    const uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN |
+            GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE;
+    mCaptureScreenBuffer = new GraphicBuffer(renderArea.getReqWidth(), renderArea.getReqHeight(),
+                                             HAL_PIXEL_FORMAT_RGBA_8888, 1, usage, "screenshot");
+
+    int fd = -1;
+    status_t result =
+            mFlinger.captureScreenImplLocked(renderArea, traverseLayers, mCaptureScreenBuffer.get(),
+                                             useIdentityTransform, forSystem, &fd);
+    if (fd >= 0) {
+        close(fd);
+    }
+
+    EXPECT_EQ(NO_ERROR, result);
+
+    LayerCase::cleanup(this);
+}
+
+/* ------------------------------------------------------------------------
+ * Variants for each display configuration which can be tested
+ */
+
+template <typename Derived>
+struct BaseDisplayVariant {
+    static constexpr bool IS_SECURE = true;
+    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_NORMAL;
+
+    static void setupPreconditions(CompositionTest* test) {
+        FakeHwcDisplayInjector(DisplayDevice::DISPLAY_PRIMARY, HWC2::DisplayType::Physical)
+                .setCapabilities(&test->mDefaultCapabilities)
+                .inject(&test->mFlinger, test->mComposer);
+
+        test->mDisplay = FakeDisplayDeviceInjector(test->mFlinger, DisplayDevice::DISPLAY_PRIMARY,
+                                                   DisplayDevice::DISPLAY_PRIMARY)
+                                 .setDisplaySize(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT)
+                                 .setDisplaySurface(test->mDisplaySurface)
+                                 .setRenderSurface(std::unique_ptr<renderengine::Surface>(
+                                         test->mRenderSurface))
+                                 .setSecure(Derived::IS_SECURE)
+                                 .setPowerMode(Derived::INIT_POWER_MODE)
+                                 .inject();
+        test->mDisplay->setLayerStack(DEFAULT_LAYER_STACK);
+    }
+
+    template <typename Case>
+    static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+                .Times(1);
+        EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
+        EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, getReleaseFences(HWC_DISPLAY, _, _)).Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+        EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+
+        EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+                .WillOnce(Return(true));
+        EXPECT_CALL(*test->mRenderEngine,
+                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                             ui::Transform::ROT_0))
+                .Times(1);
+
+        EXPECT_CALL(*test->mDisplaySurface, onFrameCommitted()).Times(1);
+        EXPECT_CALL(*test->mDisplaySurface, advanceFrame()).Times(1);
+
+        Case::CompositionType::setupHwcSetCallExpectations(test);
+        Case::CompositionType::setupHwcGetCallExpectations(test);
+    }
+
+    template <typename Case>
+    static void setupCommonScreensCaptureCallExpectations(CompositionTest* test) {
+        // Called once with a non-null value to set a framebuffer, and then
+        // again with nullptr to clear it.
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(NotNull())).WillOnce(Return(true));
+        EXPECT_CALL(*test->mReFrameBuffer, setNativeWindowBuffer(IsNull())).WillOnce(Return(true));
+
+        EXPECT_CALL(*test->mRenderEngine, checkErrors()).WillRepeatedly(Return());
+        EXPECT_CALL(*test->mRenderEngine, createFramebuffer())
+                .WillOnce(Return(
+                        ByMove(std::unique_ptr<renderengine::Framebuffer>(test->mReFrameBuffer))));
+        EXPECT_CALL(*test->mRenderEngine, bindFrameBuffer(test->mReFrameBuffer)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, unbindFrameBuffer(test->mReFrameBuffer)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, clearWithColor(0, 0, 0, 1)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, flush()).WillOnce(Return(ByMove(base::unique_fd())));
+        EXPECT_CALL(*test->mRenderEngine, finish()).WillOnce(Return(true));
+
+        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::SRGB)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+                .Times(1);
+        // This expectation retires on saturation as setViewportAndProjection is
+        // called an extra time for the code path this setup is for.
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mRenderEngine,
+                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                             ui::Transform::ROT_0))
+                .Times(1)
+                .RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1);
+    }
+
+    static void setupNonEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, beginFrame(true)).Times(1);
+    }
+
+    static void setupEmptyFrameCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, beginFrame(false)).Times(1);
+    }
+
+    static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC)).Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
+                .Times(1);
+        EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+                .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+
+        EXPECT_CALL(*test->mRenderEngine, setOutputDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setDisplayMaxLuminance(DEFAULT_DISPLAY_MAX_LUMINANCE))
+                .Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setupColorTransform(_)).Times(2);
+        // These expectations retire on saturation as the code path these
+        // expectations are for appears to make an extra call to them.
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mRenderEngine,
+                    setViewportAndProjection(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT,
+                                             Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                                             ui::Transform::ROT_0))
+                .Times(1)
+                .RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderEngine, setCurrentSurface(Ref(*test->mRenderSurface)))
+                .WillOnce(Return(true))
+                .RetiresOnSaturation();
+        EXPECT_CALL(*test->mRenderSurface, swapBuffers()).Times(1);
+    }
+
+    template <typename Case>
+    static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupRECompositionCallExpectations(test);
+    }
+
+    template <typename Case>
+    static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupREScreenshotCompositionCallExpectations(test);
+
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+    }
+};
+
+struct DefaultDisplaySetupVariant : public BaseDisplayVariant<DefaultDisplaySetupVariant> {};
+
+struct InsecureDisplaySetupVariant : public BaseDisplayVariant<InsecureDisplaySetupVariant> {
+    static constexpr bool IS_SECURE = false;
+
+    template <typename Case>
+    static void setupRELayerCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupInsecureRECompositionCallExpectations(test);
+
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    template <typename Case>
+    static void setupRELayerScreenshotCompositionCallExpectations(CompositionTest* test) {
+        Case::Layer::setupInsecureREScreenshotCompositionCallExpectations(test);
+
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+    }
+};
+
+struct PoweredOffDisplaySetupVariant : public BaseDisplayVariant<PoweredOffDisplaySetupVariant> {
+    static constexpr int INIT_POWER_MODE = HWC_POWER_MODE_OFF;
+
+    template <typename Case>
+    static void setupCommonCompositionCallExpectations(CompositionTest* test) {
+        // TODO: This seems like an unnecessary call if display is powered off.
+        EXPECT_CALL(*test->mComposer,
+                    setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
+                .Times(1);
+
+        // TODO: This seems like an unnecessary call if display is powered off.
+        Case::CompositionType::setupHwcSetCallExpectations(test);
+    }
+
+    static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        // TODO: This seems like an unnecessary call if display is powered off.
+        EXPECT_CALL(*test->mDisplaySurface, getClientTargetAcquireFence())
+                .WillRepeatedly(ReturnRef(test->mClientTargetAcquireFence));
+    }
+
+    template <typename Case>
+    static void setupRELayerCompositionCallExpectations(CompositionTest*) {}
+};
+
+/* ------------------------------------------------------------------------
+ * Variants for each layer configuration which can be tested
+ */
+
+template <typename LayerProperties>
+struct BaseLayerProperties {
+    static constexpr uint32_t WIDTH = 100;
+    static constexpr uint32_t HEIGHT = 100;
+    static constexpr PixelFormat FORMAT = PIXEL_FORMAT_RGBA_8888;
+    static constexpr uint64_t USAGE =
+            GraphicBuffer::USAGE_SW_READ_NEVER | GraphicBuffer::USAGE_SW_WRITE_NEVER;
+    static constexpr android_dataspace DATASPACE = HAL_DATASPACE_UNKNOWN;
+    static constexpr uint32_t SCALING_MODE = 0;
+    static constexpr uint32_t TRANSFORM = 0;
+    static constexpr uint32_t LAYER_FLAGS = 0;
+    static constexpr float COLOR[] = {1.f, 1.f, 1.f, 1.f};
+    static constexpr IComposerClient::BlendMode BLENDMODE =
+            IComposerClient::BlendMode::PREMULTIPLIED;
+
+    static void enqueueBuffer(CompositionTest*, sp<BufferQueueLayer> layer) {
+        auto producer = layer->getProducer();
+
+        IGraphicBufferProducer::QueueBufferOutput qbo;
+        status_t result = producer->connect(nullptr, NATIVE_WINDOW_API_EGL, false, &qbo);
+        if (result != NO_ERROR) {
+            ALOGE("Failed to connect() (%d)", result);
+            return;
+        }
+
+        int slot;
+        sp<Fence> fence;
+        result = producer->dequeueBuffer(&slot, &fence, LayerProperties::WIDTH,
+                                         LayerProperties::HEIGHT, LayerProperties::FORMAT,
+                                         LayerProperties::USAGE, nullptr, nullptr);
+        if (result != IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
+            ALOGE("Failed to dequeueBuffer() (%d)", result);
+            return;
+        }
+
+        sp<GraphicBuffer> buffer;
+        result = producer->requestBuffer(slot, &buffer);
+        if (result != NO_ERROR) {
+            ALOGE("Failed to requestBuffer() (%d)", result);
+            return;
+        }
+
+        IGraphicBufferProducer::QueueBufferInput qbi(systemTime(), false /* isAutoTimestamp */,
+                                                     LayerProperties::DATASPACE,
+                                                     Rect(LayerProperties::WIDTH,
+                                                          LayerProperties::HEIGHT),
+                                                     LayerProperties::SCALING_MODE,
+                                                     LayerProperties::TRANSFORM, Fence::NO_FENCE);
+        result = producer->queueBuffer(slot, qbi, &qbo);
+        if (result != NO_ERROR) {
+            ALOGE("Failed to queueBuffer (%d)", result);
+            return;
+        }
+    }
+
+    static void setupLatchedBuffer(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        // TODO: Eliminate the complexity of actually creating a buffer
+        EXPECT_CALL(*test->mRenderEngine, getMaxTextureSize()).WillOnce(Return(16384));
+        EXPECT_CALL(*test->mRenderEngine, getMaxViewportDims()).WillOnce(Return(16384));
+        status_t err =
+                layer->setDefaultBufferProperties(LayerProperties::WIDTH, LayerProperties::HEIGHT,
+                                                  LayerProperties::FORMAT);
+        ASSERT_EQ(NO_ERROR, err);
+        Mock::VerifyAndClear(test->mRenderEngine);
+
+        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+        enqueueBuffer(test, layer);
+        Mock::VerifyAndClear(test->mMessageQueue);
+
+        EXPECT_CALL(*test->mRenderEngine, isCurrent()).WillRepeatedly(Return(true));
+        EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
+        EXPECT_CALL(*test->mRenderEngine, createImage())
+                .WillOnce(Return(ByMove(std::unique_ptr<renderengine::Image>(test->mReImage))));
+        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, checkErrors()).Times(1);
+        EXPECT_CALL(*test->mReImage, setNativeWindowBuffer(_, false)).WillOnce(Return(true));
+        bool ignoredRecomputeVisibleRegions;
+        layer->latchBuffer(ignoredRecomputeVisibleRegions, 0);
+        Mock::VerifyAndClear(test->mRenderEngine);
+        Mock::VerifyAndClear(test->mReImage);
+    }
+
+    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        setupLatchedBuffer(test, layer);
+    }
+
+    static void setupBufferLayerPostFrameCallExpectations(CompositionTest* test) {
+        // BufferLayer::onPostComposition(), when there is no present fence
+        EXPECT_CALL(*test->mComposer, getActiveConfig(HWC_DISPLAY, _))
+                .WillOnce(DoAll(SetArgPointee<1>(DEFAULT_CONFIG_ID), Return(Error::NONE)));
+    }
+
+    static void setupHwcSetGeometryCallExpectations(CompositionTest* test) {
+        // TODO: Coverage of other values
+        EXPECT_CALL(*test->mComposer,
+                    setLayerBlendMode(HWC_DISPLAY, HWC_LAYER, LayerProperties::BLENDMODE))
+                .Times(1);
+        // TODO: Coverage of other values for origin
+        EXPECT_CALL(*test->mComposer,
+                    setLayerDisplayFrame(HWC_DISPLAY, HWC_LAYER,
+                                         IComposerClient::Rect({0, 0, LayerProperties::WIDTH,
+                                                                LayerProperties::HEIGHT})))
+                .Times(1);
+        EXPECT_CALL(*test->mComposer,
+                    setLayerPlaneAlpha(HWC_DISPLAY, HWC_LAYER, LayerProperties::COLOR[3]))
+                .Times(1);
+        // TODO: Coverage of other values
+        EXPECT_CALL(*test->mComposer, setLayerZOrder(HWC_DISPLAY, HWC_LAYER, 0u)).Times(1);
+        // TODO: Coverage of other values
+        EXPECT_CALL(*test->mComposer, setLayerInfo(HWC_DISPLAY, HWC_LAYER, 0u, 0u)).Times(1);
+
+        // These expectations retire on saturation as the code path these
+        // expectations are for appears to make an extra call to them.
+        // TODO: Investigate this extra call
+        EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
+                .Times(1)
+                .RetiresOnSaturation();
+    }
+
+    static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                       IComposerClient::FRect({0.f, 0.f, LayerProperties::WIDTH,
+                                                               LayerProperties::HEIGHT})))
+                .Times(1);
+    }
+
+    static void setupHwcSetSourceCropColorCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                       IComposerClient::FRect({0.f, 0.f, 0.f, 0.f})))
+                .Times(1);
+    }
+
+    static void setupHwcSetPerFrameCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerVisibleRegion(HWC_DISPLAY, HWC_LAYER,
+                                          std::vector<IComposerClient::Rect>({IComposerClient::Rect(
+                                                  {0, 0, LayerProperties::WIDTH,
+                                                   LayerProperties::HEIGHT})})))
+                .Times(1);
+    }
+
+    static void setupHwcSetPerFrameColorCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+
+        // TODO: use COLOR
+        EXPECT_CALL(*test->mComposer,
+                    setLayerColor(HWC_DISPLAY, HWC_LAYER,
+                                  IComposerClient::Color({0xff, 0xff, 0xff, 0xff})))
+                .Times(1);
+
+        // TODO: ColorLayer::onPreComposition() always returns true, triggering an
+        // extra layer update in SurfaceFlinger::preComposition(). This seems
+        // wrong on the surface.
+        EXPECT_CALL(*test->mMessageQueue, invalidate()).Times(1);
+    }
+
+    static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+        EXPECT_CALL(*test->mComposer, setLayerBuffer(HWC_DISPLAY, HWC_LAYER, _, _, _)).Times(1);
+
+        setupBufferLayerPostFrameCallExpectations(test);
+    }
+
+    static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine,
+                    setupLayerBlending(true, false, false,
+                                       half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+                                             LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+                .Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setupLayerTexturing(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+        // This call retires on saturation as the code that renders a texture disables the state,
+        // along with a top-level disable to ensure it is disabled for non-buffer layers.
+        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+    }
+
+    static void setupREBufferCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+
+        // TODO - Investigate and eliminate these differences between display
+        // composition and screenshot composition.
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+        setupREBufferCompositionCallExpectations(test);
+    }
+
+    static void setupREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+    }
+
+    static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCommonCallExpectations(test);
+    }
+
+    static void setupREColorCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, disableScissor()).Times(1);
+    }
+
+    static void setupREColorCompositionCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine,
+                    setupLayerBlending(true, false, true,
+                                       half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+                                             LayerProperties::COLOR[2], LayerProperties::COLOR[3])))
+                .Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+    }
+
+    static void setupREColorScreenshotCompositionCallExpectations(CompositionTest* test) {
+        setupREColorCompositionCallExpectations(test);
+    }
+};
+
+struct DefaultLayerProperties : public BaseLayerProperties<DefaultLayerProperties> {};
+
+struct ColorLayerProperties : public BaseLayerProperties<ColorLayerProperties> {};
+
+struct SidebandLayerProperties : public BaseLayerProperties<SidebandLayerProperties> {
+    using Base = BaseLayerProperties<SidebandLayerProperties>;
+    static constexpr IComposerClient::BlendMode BLENDMODE = IComposerClient::BlendMode::NONE;
+
+    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        sp<NativeHandle> stream =
+                NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
+                                     false);
+        test->mFlinger.setLayerSidebandStream(layer, stream);
+    }
+
+    static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSourceCrop(HWC_DISPLAY, HWC_LAYER,
+                                       IComposerClient::FRect({0.f, 0.f, -1.f, -1.f})))
+                .Times(1);
+    }
+
+    static void setupHwcSetPerFrameBufferCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerSidebandStream(HWC_DISPLAY, HWC_LAYER,
+                                           reinterpret_cast<native_handle_t*>(
+                                                   DEFAULT_SIDEBAND_STREAM)))
+                .WillOnce(Return(Error::NONE));
+
+        EXPECT_CALL(*test->mComposer, setLayerSurfaceDamage(HWC_DISPLAY, HWC_LAYER, _)).Times(1);
+    }
+
+    static void setupREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, setupFillWithColor(0, 0, 0, 1)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+    }
+};
+
+struct SecureLayerProperties : public BaseLayerProperties<SecureLayerProperties> {
+    using Base = BaseLayerProperties<SecureLayerProperties>;
+
+    static constexpr uint32_t LAYER_FLAGS = ISurfaceComposerClient::eSecure;
+
+    static void setupInsecureREBufferCompositionCommonCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mRenderEngine, bindExternalTextureImage(DEFAULT_TEXTURE_ID, _)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setupLayerBlackedOut()).Times(1);
+
+        EXPECT_CALL(*test->mRenderEngine,
+                    setupLayerBlending(true, false, false,
+                                       half4(Base::COLOR[0], Base::COLOR[1], Base::COLOR[2],
+                                             Base::COLOR[3])))
+                .Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceDataSpace(ui::Dataspace::UNKNOWN)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, drawMesh(_)).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, disableBlending()).Times(1);
+        EXPECT_CALL(*test->mRenderEngine, setSourceY410BT2020(false)).Times(1);
+        // This call retires on saturation as the code that renders a texture disables the state,
+        // along with a top-level disable to ensure it is disabled for non-buffer layers.
+        EXPECT_CALL(*test->mRenderEngine, disableTexturing()).Times(1).RetiresOnSaturation();
+    }
+
+    static void setupInsecureREBufferCompositionCallExpectations(CompositionTest* test) {
+        setupInsecureREBufferCompositionCommonCallExpectations(test);
+        Base::setupBufferLayerPostFrameCallExpectations(test);
+    }
+
+    static void setupInsecureREBufferScreenshotCompositionCallExpectations(CompositionTest* test) {
+        setupInsecureREBufferCompositionCommonCallExpectations(test);
+    }
+};
+
+struct CursorLayerProperties : public BaseLayerProperties<CursorLayerProperties> {
+    using Base = BaseLayerProperties<CursorLayerProperties>;
+
+    static void setupLayerState(CompositionTest* test, sp<BufferQueueLayer> layer) {
+        Base::setupLayerState(test, layer);
+        test->mFlinger.setLayerPotentialCursor(layer, true);
+    }
+};
+
+struct NoLayerVariant {
+    using FlingerLayerType = sp<BufferQueueLayer>;
+
+    static FlingerLayerType createLayer(CompositionTest*) { return FlingerLayerType(); }
+    static void injectLayer(CompositionTest*, FlingerLayerType) {}
+    static void cleanupInjectedLayers(CompositionTest*) {}
+
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+    static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+template <typename LayerProperties>
+struct BaseLayerVariant {
+    template <typename L, typename F>
+    static sp<L> createLayerWithFactory(CompositionTest* test, F factory) {
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(0);
+
+        sp<L> layer = factory();
+
+        Mock::VerifyAndClear(test->mComposer);
+        Mock::VerifyAndClear(test->mRenderEngine);
+        Mock::VerifyAndClear(test->mMessageQueue);
+
+        auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+        layerDrawingState.layerStack = DEFAULT_LAYER_STACK;
+        layerDrawingState.active.w = 100;
+        layerDrawingState.active.h = 100;
+        layerDrawingState.color = half4(LayerProperties::COLOR[0], LayerProperties::COLOR[1],
+                                        LayerProperties::COLOR[2], LayerProperties::COLOR[3]);
+
+        layer->setVisibleRegion(Region(Rect(0, 0, 100, 100)));
+
+        return layer;
+    }
+
+    static void injectLayer(CompositionTest* test, sp<Layer> layer) {
+        EXPECT_CALL(*test->mComposer, createLayer(HWC_DISPLAY, _))
+                .WillOnce(DoAll(SetArgPointee<1>(HWC_LAYER), Return(Error::NONE)));
+
+        layer->createHwcLayer(test->mFlinger.mFlinger->getBE().mHwc.get(), test->mDisplay->getId());
+
+        Mock::VerifyAndClear(test->mComposer);
+
+        Vector<sp<Layer>> layers;
+        layers.add(layer);
+        test->mDisplay->setVisibleLayersSortedByZ(layers);
+        test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
+    }
+
+    static void cleanupInjectedLayers(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, destroyLayer(HWC_DISPLAY, HWC_LAYER))
+                .WillOnce(Return(Error::NONE));
+        for (auto layer : test->mFlinger.mutableDrawingState().layersSortedByZ) {
+            layer->destroyHwcLayer(test->mDisplay->getId());
+        }
+        test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
+    }
+};
+
+template <typename LayerProperties>
+struct ColorLayerVariant : public BaseLayerVariant<LayerProperties> {
+    using Base = BaseLayerVariant<LayerProperties>;
+    using FlingerLayerType = sp<ColorLayer>;
+
+    static FlingerLayerType createLayer(CompositionTest* test) {
+        FlingerLayerType layer = Base::template createLayerWithFactory<ColorLayer>(test, [test]() {
+            return new ColorLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+                                  String8("test-layer"), LayerProperties::WIDTH,
+                                  LayerProperties::HEIGHT, LayerProperties::LAYER_FLAGS);
+        });
+        return layer;
+    }
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREColorCompositionCommonCallExpectations(test);
+        LayerProperties::setupREColorCompositionCallExpectations(test);
+    }
+
+    static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREColorScreenshotCompositionCallExpectations(test);
+    }
+
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+        LayerProperties::setupHwcSetGeometryCallExpectations(test);
+        LayerProperties::setupHwcSetSourceCropColorCallExpectations(test);
+    }
+
+    static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+        LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+        LayerProperties::setupHwcSetPerFrameColorCallExpectations(test);
+    }
+};
+
+template <typename LayerProperties>
+struct BufferLayerVariant : public BaseLayerVariant<LayerProperties> {
+    using Base = BaseLayerVariant<LayerProperties>;
+    using FlingerLayerType = sp<BufferQueueLayer>;
+
+    static FlingerLayerType createLayer(CompositionTest* test) {
+        test->mFlinger.mutableTexturePool().push_back(DEFAULT_TEXTURE_ID);
+
+        FlingerLayerType layer =
+                Base::template createLayerWithFactory<BufferQueueLayer>(test, [test]() {
+                    return new BufferQueueLayer(test->mFlinger.mFlinger.get(), sp<Client>(),
+                                                String8("test-layer"), LayerProperties::WIDTH,
+                                                LayerProperties::HEIGHT,
+                                                LayerProperties::LAYER_FLAGS);
+                });
+
+        LayerProperties::setupLayerState(test, layer);
+
+        return layer;
+    }
+
+    static void cleanupInjectedLayers(CompositionTest* test) {
+        EXPECT_CALL(*test->mMessageQueue, postMessage(_, 0)).Times(2);
+        Base::cleanupInjectedLayers(test);
+    }
+
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+        LayerProperties::setupHwcSetGeometryCallExpectations(test);
+        LayerProperties::setupHwcSetSourceCropBufferCallExpectations(test);
+    }
+
+    static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+        LayerProperties::setupHwcSetPerFrameCallExpectations(test);
+        LayerProperties::setupHwcSetPerFrameBufferCallExpectations(test);
+    }
+
+    static void setupRECompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferCompositionCallExpectations(test);
+    }
+
+    static void setupInsecureRECompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupInsecureREBufferCompositionCallExpectations(test);
+    }
+
+    static void setupREScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupREBufferScreenshotCompositionCallExpectations(test);
+    }
+
+    static void setupInsecureREScreenshotCompositionCallExpectations(CompositionTest* test) {
+        LayerProperties::setupInsecureREBufferScreenshotCompositionCallExpectations(test);
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to control how the composition type is changed
+ */
+
+struct NoCompositionTypeVariant {
+    static void setupHwcSetCallExpectations(CompositionTest*) {}
+
+    static void setupHwcGetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+    }
+};
+
+template <IComposerClient::Composition CompositionType>
+struct KeepCompositionTypeVariant {
+    static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(CompositionType);
+
+    static void setupHwcSetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, CompositionType))
+                .Times(1);
+    }
+
+    static void setupHwcGetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _)).Times(1);
+    }
+};
+
+template <IComposerClient::Composition InitialCompositionType,
+          IComposerClient::Composition FinalCompositionType>
+struct ChangeCompositionTypeVariant {
+    static constexpr HWC2::Composition TYPE = static_cast<HWC2::Composition>(FinalCompositionType);
+
+    static void setupHwcSetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer,
+                    setLayerCompositionType(HWC_DISPLAY, HWC_LAYER, InitialCompositionType))
+                .Times(1);
+    }
+
+    static void setupHwcGetCallExpectations(CompositionTest* test) {
+        EXPECT_CALL(*test->mComposer, getChangedCompositionTypes(HWC_DISPLAY, _, _))
+                .WillOnce(DoAll(SetArgPointee<1>(std::vector<Hwc2::Layer>{
+                                        static_cast<Hwc2::Layer>(HWC_LAYER)}),
+                                SetArgPointee<2>(std::vector<IComposerClient::Composition>{
+                                        FinalCompositionType}),
+                                Return(Error::NONE)));
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Variants to select how the composition is expected to be handled
+ */
+
+struct CompositionResultBaseVariant {
+    static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest* test) {
+        Case::Layer::setupCallExpectationsForDirtyGeometry(test);
+    }
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyFrame(CompositionTest* test) {
+        Case::Layer::setupCallExpectationsForDirtyFrame(test);
+    }
+};
+
+struct NoCompositionResultVariant : public CompositionResultBaseVariant {
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcCompositionCallExpectations(test);
+    }
+};
+
+struct HwcCompositionResultVariant : public CompositionResultBaseVariant {
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupHwcCompositionCallExpectations(test);
+    }
+};
+
+struct RECompositionResultVariant : public CompositionResultBaseVariant {
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+        Case::Display::setupRECompositionCallExpectations(test);
+        Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+    }
+};
+
+struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+    static void setupLayerState(CompositionTest*, sp<Layer> layer) {
+        layer->forceClientComposition(DisplayDevice::DISPLAY_PRIMARY);
+    }
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
+
+    template <typename Case>
+    static void setupCallExpectationsForDirtyFrame(CompositionTest*) {}
+};
+
+struct EmptyScreenshotResultVariant {
+    static void setupLayerState(CompositionTest*, sp<Layer>) {}
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest*) {}
+};
+
+struct REScreenshotResultVariant : public EmptyScreenshotResultVariant {
+    using Base = EmptyScreenshotResultVariant;
+
+    template <typename Case>
+    static void setupCallExpectations(CompositionTest* test) {
+        Base::template setupCallExpectations<Case>(test);
+        Case::Display::template setupRELayerScreenshotCompositionCallExpectations<Case>(test);
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition test case, containing all the variants being tested
+ */
+
+template <typename DisplayCase, typename LayerCase, typename CompositionTypeCase,
+          typename CompositionResultCase>
+struct CompositionCase {
+    using ThisCase =
+            CompositionCase<DisplayCase, LayerCase, CompositionTypeCase, CompositionResultCase>;
+    using Display = DisplayCase;
+    using Layer = LayerCase;
+    using CompositionType = CompositionTypeCase;
+    using CompositionResult = CompositionResultCase;
+
+    static void setupCommon(CompositionTest* test) {
+        Display::setupPreconditions(test);
+
+        auto layer = Layer::createLayer(test);
+        Layer::injectLayer(test, layer);
+        CompositionResult::setupLayerState(test, layer);
+    }
+
+    static void setupForDirtyGeometry(CompositionTest* test) {
+        setupCommon(test);
+
+        Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+        CompositionResult::template setupCallExpectationsForDirtyGeometry<ThisCase>(test);
+        CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+        CompositionResult::template setupCallExpectations<ThisCase>(test);
+    }
+
+    static void setupForDirtyFrame(CompositionTest* test) {
+        setupCommon(test);
+
+        Display::template setupCommonCompositionCallExpectations<ThisCase>(test);
+        CompositionResult::template setupCallExpectationsForDirtyFrame<ThisCase>(test);
+        CompositionResult::template setupCallExpectations<ThisCase>(test);
+    }
+
+    static void setupForScreenCapture(CompositionTest* test) {
+        setupCommon(test);
+
+        Display::template setupCommonScreensCaptureCallExpectations<ThisCase>(test);
+        CompositionResult::template setupCallExpectations<ThisCase>(test);
+    }
+
+    static void cleanup(CompositionTest* test) {
+        Layer::cleanupInjectedLayers(test);
+
+        for (auto& hwcDisplay : test->mFlinger.mFakeHwcDisplays) {
+            hwcDisplay->mutableLayers().clear();
+        }
+
+        test->mDisplay->setVisibleLayersSortedByZ(Vector<sp<android::Layer>>());
+    }
+};
+
+/* ------------------------------------------------------------------------
+ * Composition cases to test
+ */
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+                            NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+                            NoCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, noLayersDoesMinimalWorkToCaptureScreen) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, NoLayerVariant, NoCompositionTypeVariant,
+                            EmptyScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Simple buffer layers
+ */
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedNormalBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedNormalBufferLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Single-color layers
+ */
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedColorLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedColorLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::SOLID_COLOR,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenColorLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, ColorLayerVariant<ColorLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Layers with sideband buffers
+ */
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSidebandBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::SIDEBAND>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSidebandBufferLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::SIDEBAND,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSidebandBufferLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SidebandLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Layers with ISurfaceComposerClient::eSecure, on a secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedSecureBufferLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnSecureDisplay) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Layers with ISurfaceComposerClient::eSecure, on a non-secure display
+ */
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedSecureBufferLayerOnInsecureDisplayWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CLIENT>,
+                            ForcedClientCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenSecureBufferLayerOnInsecureDisplay) {
+    captureScreenComposition<
+            CompositionCase<InsecureDisplaySetupVariant, BufferLayerVariant<SecureLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Cursor layers
+ */
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, HWCComposedCursorLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            KeepCompositionTypeVariant<IComposerClient::Composition::CURSOR>,
+                            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, REComposedCursorLayer) {
+    displayRefreshCompositionDirtyFrame<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            ChangeCompositionTypeVariant<IComposerClient::Composition::CURSOR,
+                                                         IComposerClient::Composition::CLIENT>,
+                            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenCursorLayer) {
+    captureScreenComposition<
+            CompositionCase<DefaultDisplaySetupVariant, BufferLayerVariant<CursorLayerProperties>,
+                            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+/* ------------------------------------------------------------------------
+ *  Simple buffer layer on a display which is powered off.
+ */
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyGeometry) {
+    displayRefreshCompositionDirtyGeometry<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffHWCComposedNormalBufferLayerWithDirtyFrame) {
+    displayRefreshCompositionDirtyFrame<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            KeepCompositionTypeVariant<IComposerClient::Composition::DEVICE>,
+            HwcCompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, displayOffREComposedNormalBufferLayer) {
+    displayRefreshCompositionDirtyFrame<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            ChangeCompositionTypeVariant<IComposerClient::Composition::DEVICE,
+                                         IComposerClient::Composition::CLIENT>,
+            RECompositionResultVariant>>();
+}
+
+TEST_F(CompositionTest, captureScreenNormalBufferLayerOnPoweredOffDisplay) {
+    captureScreenComposition<CompositionCase<
+            PoweredOffDisplaySetupVariant, BufferLayerVariant<DefaultLayerProperties>,
+            NoCompositionTypeVariant, REScreenshotResultVariant>>();
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index c809e82..df0d982 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -40,7 +40,7 @@
               : mEventThread(std::move(eventThread)) {}
 
         std::unique_ptr<EventThread> makeEventThread(
-                const char* /* connectionName */, DispSync* /* dispSync */,
+                const std::string& /* connectionName */, DispSync* /* dispSync */,
                 nsecs_t /* phaseOffsetNs */,
                 impl::EventThread::ResyncWithRateLimitCallback /* resyncCallback */,
                 impl::EventThread::InterceptVSyncsCallback /* interceptCallback */) override {
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 1bba480..341734c 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include "DisplayDevice.h"
+#include "Layer.h"
 #include "SurfaceFlinger.h"
 
 namespace android {
@@ -56,6 +57,21 @@
 
     using HotplugEvent = SurfaceFlinger::HotplugEvent;
 
+    auto& mutableLayerCurrentState(sp<Layer> layer) { return layer->mCurrentState; }
+    auto& mutableLayerDrawingState(sp<Layer> layer) { return layer->mDrawingState; }
+
+    void setLayerSidebandStream(sp<Layer> layer, sp<NativeHandle> sidebandStream) {
+        layer->getBE().compositionInfo.hwc.sidebandStream = sidebandStream;
+    }
+
+    void setLayerCompositionType(sp<Layer> layer, HWC2::Composition type) {
+        layer->getBE().mHwcLayers[DisplayDevice::DISPLAY_PRIMARY].compositionType = type;
+    };
+
+    void setLayerPotentialCursor(sp<Layer> layer, bool potentialCursor) {
+        layer->mPotentialCursor = potentialCursor;
+    }
+
     /* ------------------------------------------------------------------------
      * Forwarding for functions being tested
      */
@@ -96,6 +112,21 @@
         return mFlinger->setPowerModeInternal(display, mode, stateLockHeld);
     }
 
+    auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); }
+
+    auto captureScreenImplLocked(const RenderArea& renderArea,
+                                 TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer,
+                                 bool useIdentityTransform, bool forSystem, int* outSyncFd) {
+        return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
+                                                 useIdentityTransform, forSystem, outSyncFd);
+    }
+
+    auto traverseLayersInDisplay(const sp<const DisplayDevice>& display, int32_t minLayerZ,
+                                 int32_t maxLayerZ, const LayerVector::Visitor& visitor) {
+        return mFlinger->SurfaceFlinger::traverseLayersInDisplay(display, minLayerZ, maxLayerZ,
+                                                                 visitor);
+    }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
@@ -116,20 +147,22 @@
     auto& mutablePrimaryDisplayOrientation() { return SurfaceFlinger::primaryDisplayOrientation; }
     auto& mutableUseColorManagement() { return SurfaceFlinger::useColorManagement; }
 
-    auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
-    auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
+    auto& mutableDisplays() { return mFlinger->mDisplays; }
+    auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
     auto& mutableDrawingState() { return mFlinger->mDrawingState; }
     auto& mutableEventControlThread() { return mFlinger->mEventControlThread; }
     auto& mutableEventQueue() { return mFlinger->mEventQueue; }
     auto& mutableEventThread() { return mFlinger->mEventThread; }
+    auto& mutableGeometryInvalid() { return mFlinger->mGeometryInvalid; }
     auto& mutableHWVsyncAvailable() { return mFlinger->mHWVsyncAvailable; }
     auto& mutableInterceptor() { return mFlinger->mInterceptor; }
     auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
     auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
     auto& mutablePrimaryDispSync() { return mFlinger->mPrimaryDispSync; }
     auto& mutablePrimaryHWVsyncEnabled() { return mFlinger->mPrimaryHWVsyncEnabled; }
+    auto& mutableTexturePool() { return mFlinger->mTexturePool; }
     auto& mutableTransactionFlags() { return mFlinger->mTransactionFlags; }
     auto& mutableUseHwcVirtualDisplays() { return mFlinger->mUseHwcVirtualDisplays; }
 
@@ -175,6 +208,7 @@
 
         auto& mutableIsConnected() { return this->mIsConnected; }
         auto& mutableConfigs() { return this->mConfigs; }
+        auto& mutableLayers() { return this->mLayers; }
     };
 
     class FakeHwcDisplayInjector {
@@ -324,14 +358,25 @@
             return *this;
         }
 
+        auto& setDisplaySize(int width, int height) {
+            mWidth = width;
+            mHeight = height;
+            return *this;
+        }
+
+        auto& setPowerMode(int mode) {
+            mPowerMode = mode;
+            return *this;
+        }
+
         sp<DisplayDevice> inject() {
             std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hdrAndRenderIntents;
             sp<DisplayDevice> device =
                     new DisplayDevice(mFlinger.mFlinger.get(), mType, mDisplayId, mSecure,
                                       mDisplayToken, mNativeWindow, mDisplaySurface,
-                                      std::move(mRenderSurface), 0, 0,
+                                      std::move(mRenderSurface), mWidth, mHeight,
                                       DisplayState::eOrientationDefault, false, HdrCapabilities(),
-                                      0, hdrAndRenderIntents, HWC_POWER_MODE_NORMAL);
+                                      0, hdrAndRenderIntents, mPowerMode);
             mFlinger.mutableDisplays().emplace(mDisplayToken, device);
 
             DisplayDeviceState state;
@@ -356,6 +401,9 @@
         sp<DisplaySurface> mDisplaySurface;
         std::unique_ptr<renderengine::Surface> mRenderSurface;
         bool mSecure = false;
+        int mWidth = 0;
+        int mHeight = 0;
+        int mPowerMode = HWC_POWER_MODE_NORMAL;
     };
 
     sp<SurfaceFlinger> mFlinger = new SurfaceFlinger(SurfaceFlinger::SkipInitialization);
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
index 06ef0b2..af54df6 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.cpp
@@ -32,6 +32,9 @@
 Image::Image() = default;
 Image::~Image() = default;
 
+Framebuffer::Framebuffer() = default;
+Framebuffer::~Framebuffer() = default;
+
 } // namespace mock
 } // namespace renderengine
 } // namespace android
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 84d3c63..39ed622 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -18,6 +18,7 @@
 
 #include <gmock/gmock.h>
 
+#include <renderengine/Framebuffer.h>
 #include <renderengine/Image.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/RenderEngine.h>
@@ -103,6 +104,14 @@
                  bool(ANativeWindowBuffer* buffer, bool isProtected));
 };
 
+class Framebuffer : public renderengine::Framebuffer {
+public:
+    Framebuffer();
+    ~Framebuffer() override;
+
+    MOCK_METHOD1(setNativeWindowBuffer, bool(ANativeWindowBuffer*));
+};
+
 } // namespace mock
 } // namespace renderengine
 } // namespace android
diff --git a/vulkan/api/vulkan.api b/vulkan/api/vulkan.api
index 76eca35..8817e8d 100644
--- a/vulkan/api/vulkan.api
+++ b/vulkan/api/vulkan.api
@@ -28,7 +28,7 @@
 // API version (major.minor.patch)
 define VERSION_MAJOR 1
 define VERSION_MINOR 1
-define VERSION_PATCH 82
+define VERSION_PATCH 84
 
 // API limits
 define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
@@ -221,6 +221,10 @@
 @extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_SPEC_VERSION 1
 @extension("VK_EXT_shader_subgroup_vote") define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
 
+// 68
+@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1
+@extension("VK_EXT_astc_decode_mode") define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode"
+
 // 70
 @extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_SPEC_VERSION 2
 @extension("VK_KHR_maintenance1") define VK_KHR_MAINTENANCE1_EXTENSION_NAME "VK_KHR_maintenance1"
@@ -437,6 +441,10 @@
 @extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_SPEC_VERSION 1
 @extension("VK_AMD_shader_fragment_mask") define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
 
+// 139
+@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1
+@extension("VK_EXT_inline_uniform_block") define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block"
+
 // 141
 @extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1
 @extension("VK_EXT_shader_stencil_export") define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export"
@@ -526,8 +534,8 @@
 @extension("VK_AMD_shader_core_properties") define VK_AMD_SHADER_CORE_PROPERTIES_EXTENSION_NAME "VK_AMD_shader_core_properties"
 
 // 191
-@extension("VK_EXT_vertex_attribute_divisor") define VK_AMD_SHADER_CORE_PROPERTIES_SPEC_VERSION 1
-@extension("VK_EXT_vertex_attribute_divisor") define VK_AMD_BUFFER_MARKER_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
+@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
+@extension("VK_EXT_vertex_attribute_divisor") define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
 
 // 199
 @extension("VK_NV_shader_subgroup_partitioned") define VK_NV_SHADER_SUBGROUP_PARTITIONED_SPEC_VERSION 1
@@ -537,6 +545,10 @@
 @extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_SPEC_VERSION 2
 @extension("VK_NV_device_diagnostic_checkpoints") define VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME "VK_NV_device_diagnostic_checkpoints"
 
+// 212
+@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
+@extension("VK_KHR_vulkan_memory_model") define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
+
 /////////////
 //  Types  //
 /////////////
@@ -697,6 +709,9 @@
     VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC               = 0x00000008,
     VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC               = 0x00000009,
     VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT                     = 0x0000000a,
+
+    //@extension("VK_EXT_inline_uniform_block") // 139
+    VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT             = 1000138000,
 }
 
 enum VkQueryType {
@@ -1416,6 +1431,10 @@
     //@extension("VK_NN_vi_surface") // 63
     VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN                 = 1000062000,
 
+    //@extension("VK_EXT_astc_decode_mode") // 68
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT           = 1000067000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT  = 1000067001,
+
     //@extension("VK_KHR_device_group_creation") // 71
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES_KHR      = 1000070000,
     VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO_KHR       = 1000070001,
@@ -1595,6 +1614,12 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
     VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
 
+    //@extension("VK_EXT_inline_uniform_block") // 139
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT     = 1000138000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT   = 1000138001,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT         = 1000138002,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT  = 1000138003,
+
     //@extension("VK_EXT_sample_locations") // 144
     VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT                         = 1000143000,
     VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT       = 1000143001,
@@ -1667,10 +1692,14 @@
     //@extension("VK_EXT_vertex_attribute_divisor") // 191
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT   = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT       = 1000190001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT     = 1000190002,
 
     //@extension("VK_NV_device_diagnostic_checkpoints") // 207
     VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV                        = 1000206000,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV     = 1000206001,
+
+    //@extension("VK_KHR_vulkan_memory_model") // 212
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
 }
 
 enum VkSubpassContents {
@@ -5354,6 +5383,20 @@
     void*                                       window
 }
 
+@extension("VK_EXT_astc_decode_mode") // 68
+class VkImageViewASTCDecodeModeEXT {
+    VkStructureType                             sType
+    const void*                                 pNext
+    VkFormat                                    decodeMode
+}
+
+@extension("VK_EXT_astc_decode_mode") // 68
+class VkPhysicalDeviceASTCDecodeFeaturesEXT {
+    VkStructureType                             sType
+    void*                                       pNext
+    VkBool32                                    decodeModeSharedExponent
+}
+
 @extension("VK_KHR_device_group_creation") // 71
 class VkPhysicalDeviceGroupPropertiesKHR {
     VkStructureType                                 sType
@@ -6386,6 +6429,40 @@
     VkBool32                                        filterMinmaxImageComponentMapping
 }
 
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkPhysicalDeviceInlineUniformBlockFeaturesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        inlineUniformBlock
+    VkBool32                                        descriptorBindingInlineUniformBlockUpdateAfterBind
+}
+
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkPhysicalDeviceInlineUniformBlockPropertiesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    u32                                             maxInlineUniformBlockSize
+    u32                                             maxPerStageDescriptorInlineUniformBlocks
+    u32                                             maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks
+    u32                                             maxDescriptorSetInlineUniformBlocks
+    u32                                             maxDescriptorSetUpdateAfterBindInlineUniformBlocks
+}
+
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkWriteDescriptorSetInlineUniformBlockEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             dataSize
+    const void*                                     pData
+}
+
+@extension("VK_EXT_inline_uniform_block") // 139
+class VkDescriptorPoolInlineUniformBlockCreateInfoEXT {
+    VkStructureType                                 sType
+    const void*                                     pNext
+    u32                                             maxInlineUniformBlockBindings
+}
+
 @extension("VK_EXT_sample_locations") // 144
 class VkSampleLocationEXT {
     f32                                             x
@@ -6796,6 +6873,14 @@
     const VkVertexInputBindingDivisorDescriptionEXT*    pVertexBindingDivisors
 }
 
+@extension("VK_EXT_vertex_attribute_divisor") // 191
+class VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        vertexAttributeInstanceRateDivisor
+    VkBool32                                        vertexAttributeInstanceRateZeroDivisor
+}
+
 @extension("VK_NV_device_diagnostic_checkpoints") // 207
 class VkQueueFamilyCheckpointPropertiesNV {
     VkStructureType                                 sType
@@ -6811,6 +6896,14 @@
     void*                                           pCheckpointMarker
 }
 
+@extension("VK_KHR_vulkan_memory_model") // 212
+class VkPhysicalDeviceVulkanMemoryModelFeaturesKHR {
+    VkStructureType                                 sType
+    void*                                           pNext
+    VkBool32                                        vulkanMemoryModel
+    VkBool32                                        vulkanMemoryModelDeviceScope
+}
+
 
 ////////////////
 //  Commands  //
diff --git a/vulkan/include/vulkan/vulkan_core.h b/vulkan/include/vulkan/vulkan_core.h
index d511015..fe45014 100644
--- a/vulkan/include/vulkan/vulkan_core.h
+++ b/vulkan/include/vulkan/vulkan_core.h
@@ -43,7 +43,7 @@
 #define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
 #define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
 // Version of this file
-#define VK_HEADER_VERSION 82
+#define VK_HEADER_VERSION 84
 
 
 #define VK_NULL_HANDLE 0
@@ -305,6 +305,8 @@
     VK_STRUCTURE_TYPE_WIN32_KEYED_MUTEX_ACQUIRE_RELEASE_INFO_NV = 1000058000,
     VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT = 1000061000,
     VK_STRUCTURE_TYPE_VI_SURFACE_CREATE_INFO_NN = 1000062000,
+    VK_STRUCTURE_TYPE_IMAGE_VIEW_ASTC_DECODE_MODE_EXT = 1000067000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ASTC_DECODE_FEATURES_EXT = 1000067001,
     VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073000,
     VK_STRUCTURE_TYPE_EXPORT_MEMORY_WIN32_HANDLE_INFO_KHR = 1000073001,
     VK_STRUCTURE_TYPE_MEMORY_WIN32_HANDLE_PROPERTIES_KHR = 1000073002,
@@ -380,6 +382,10 @@
     VK_STRUCTURE_TYPE_EXTERNAL_FORMAT_ANDROID = 1000129005,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_FILTER_MINMAX_PROPERTIES_EXT = 1000130000,
     VK_STRUCTURE_TYPE_SAMPLER_REDUCTION_MODE_CREATE_INFO_EXT = 1000130001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT = 1000138000,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_PROPERTIES_EXT = 1000138001,
+    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET_INLINE_UNIFORM_BLOCK_EXT = 1000138002,
+    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_INLINE_UNIFORM_BLOCK_CREATE_INFO_EXT = 1000138003,
     VK_STRUCTURE_TYPE_SAMPLE_LOCATIONS_INFO_EXT = 1000143000,
     VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT = 1000143001,
     VK_STRUCTURE_TYPE_PIPELINE_SAMPLE_LOCATIONS_STATE_CREATE_INFO_EXT = 1000143002,
@@ -406,8 +412,11 @@
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_CORE_PROPERTIES_AMD = 1000185000,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_PROPERTIES_EXT = 1000190000,
     VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_DIVISOR_STATE_CREATE_INFO_EXT = 1000190001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VERTEX_ATTRIBUTE_DIVISOR_FEATURES_EXT = 1000190002,
     VK_STRUCTURE_TYPE_CHECKPOINT_DATA_NV = 1000206000,
     VK_STRUCTURE_TYPE_QUEUE_FAMILY_CHECKPOINT_PROPERTIES_NV = 1000206001,
+    VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_MEMORY_MODEL_FEATURES_KHR = 1000211000,
+    VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT,
     VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES,
@@ -442,6 +451,7 @@
     VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_SEMAPHORE_CREATE_INFO,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES,
     VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,
+    VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT,
     VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO_KHR = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO,
     VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES_KHR = VK_STRUCTURE_TYPE_EXTERNAL_FENCE_PROPERTIES,
     VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO_KHR = VK_STRUCTURE_TYPE_EXPORT_FENCE_CREATE_INFO,
@@ -1120,6 +1130,7 @@
     VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC = 8,
     VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC = 9,
     VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT = 10,
+    VK_DESCRIPTOR_TYPE_INLINE_UNIFORM_BLOCK_EXT = 1000138000,
     VK_DESCRIPTOR_TYPE_BEGIN_RANGE = VK_DESCRIPTOR_TYPE_SAMPLER,
     VK_DESCRIPTOR_TYPE_END_RANGE = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT,
     VK_DESCRIPTOR_TYPE_RANGE_SIZE = (VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT - VK_DESCRIPTOR_TYPE_SAMPLER + 1),
@@ -4575,7 +4586,6 @@
 
 #define VK_KHR_SURFACE_SPEC_VERSION       25
 #define VK_KHR_SURFACE_EXTENSION_NAME     "VK_KHR_surface"
-#define VK_COLORSPACE_SRGB_NONLINEAR_KHR  VK_COLOR_SPACE_SRGB_NONLINEAR_KHR
 
 
 typedef enum VkColorSpaceKHR {
@@ -4594,6 +4604,7 @@
     VK_COLOR_SPACE_ADOBERGB_NONLINEAR_EXT = 1000104012,
     VK_COLOR_SPACE_PASS_THROUGH_EXT = 1000104013,
     VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT = 1000104014,
+    VK_COLORSPACE_SRGB_NONLINEAR_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_BEGIN_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_END_RANGE_KHR = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
     VK_COLOR_SPACE_RANGE_SIZE_KHR = (VK_COLOR_SPACE_SRGB_NONLINEAR_KHR - VK_COLOR_SPACE_SRGB_NONLINEAR_KHR + 1),
@@ -5981,13 +5992,24 @@
 
 
 
+#define VK_KHR_vulkan_memory_model 1
+#define VK_KHR_VULKAN_MEMORY_MODEL_SPEC_VERSION 2
+#define VK_KHR_VULKAN_MEMORY_MODEL_EXTENSION_NAME "VK_KHR_vulkan_memory_model"
+
+typedef struct VkPhysicalDeviceVulkanMemoryModelFeaturesKHR {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           vulkanMemoryModel;
+    VkBool32           vulkanMemoryModelDeviceScope;
+} VkPhysicalDeviceVulkanMemoryModelFeaturesKHR;
+
+
+
 #define VK_EXT_debug_report 1
 VK_DEFINE_NON_DISPATCHABLE_HANDLE(VkDebugReportCallbackEXT)
 
 #define VK_EXT_DEBUG_REPORT_SPEC_VERSION  9
 #define VK_EXT_DEBUG_REPORT_EXTENSION_NAME "VK_EXT_debug_report"
-#define VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT
-#define VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT
 
 
 typedef enum VkDebugReportObjectTypeEXT {
@@ -6027,6 +6049,8 @@
     VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT = 33,
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT = 1000156000,
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT = 1000085000,
+    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_CALLBACK_EXT_EXT,
+    VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_KHR_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_YCBCR_CONVERSION_EXT,
     VK_DEBUG_REPORT_OBJECT_TYPE_BEGIN_RANGE_EXT = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT,
@@ -6431,6 +6455,24 @@
 #define VK_EXT_SHADER_SUBGROUP_VOTE_EXTENSION_NAME "VK_EXT_shader_subgroup_vote"
 
 
+#define VK_EXT_astc_decode_mode 1
+#define VK_EXT_ASTC_DECODE_MODE_SPEC_VERSION 1
+#define VK_EXT_ASTC_DECODE_MODE_EXTENSION_NAME "VK_EXT_astc_decode_mode"
+
+typedef struct VkImageViewASTCDecodeModeEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    VkFormat           decodeMode;
+} VkImageViewASTCDecodeModeEXT;
+
+typedef struct VkPhysicalDeviceASTCDecodeFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           decodeModeSharedExponent;
+} VkPhysicalDeviceASTCDecodeFeaturesEXT;
+
+
+
 #define VK_EXT_conditional_rendering 1
 #define VK_EXT_CONDITIONAL_RENDERING_SPEC_VERSION 1
 #define VK_EXT_CONDITIONAL_RENDERING_EXTENSION_NAME "VK_EXT_conditional_rendering"
@@ -6746,7 +6788,6 @@
 #define VK_EXT_display_surface_counter 1
 #define VK_EXT_DISPLAY_SURFACE_COUNTER_SPEC_VERSION 1
 #define VK_EXT_DISPLAY_SURFACE_COUNTER_EXTENSION_NAME "VK_EXT_display_surface_counter"
-#define VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES2_EXT VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_EXT
 
 
 typedef enum VkSurfaceCounterFlagBitsEXT {
@@ -7300,6 +7341,42 @@
 #define VK_AMD_SHADER_FRAGMENT_MASK_EXTENSION_NAME "VK_AMD_shader_fragment_mask"
 
 
+#define VK_EXT_inline_uniform_block 1
+#define VK_EXT_INLINE_UNIFORM_BLOCK_SPEC_VERSION 1
+#define VK_EXT_INLINE_UNIFORM_BLOCK_EXTENSION_NAME "VK_EXT_inline_uniform_block"
+
+typedef struct VkPhysicalDeviceInlineUniformBlockFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           inlineUniformBlock;
+    VkBool32           descriptorBindingInlineUniformBlockUpdateAfterBind;
+} VkPhysicalDeviceInlineUniformBlockFeaturesEXT;
+
+typedef struct VkPhysicalDeviceInlineUniformBlockPropertiesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    uint32_t           maxInlineUniformBlockSize;
+    uint32_t           maxPerStageDescriptorInlineUniformBlocks;
+    uint32_t           maxPerStageDescriptorUpdateAfterBindInlineUniformBlocks;
+    uint32_t           maxDescriptorSetInlineUniformBlocks;
+    uint32_t           maxDescriptorSetUpdateAfterBindInlineUniformBlocks;
+} VkPhysicalDeviceInlineUniformBlockPropertiesEXT;
+
+typedef struct VkWriteDescriptorSetInlineUniformBlockEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           dataSize;
+    const void*        pData;
+} VkWriteDescriptorSetInlineUniformBlockEXT;
+
+typedef struct VkDescriptorPoolInlineUniformBlockCreateInfoEXT {
+    VkStructureType    sType;
+    const void*        pNext;
+    uint32_t           maxInlineUniformBlockBindings;
+} VkDescriptorPoolInlineUniformBlockCreateInfoEXT;
+
+
+
 #define VK_EXT_shader_stencil_export 1
 #define VK_EXT_SHADER_STENCIL_EXPORT_SPEC_VERSION 1
 #define VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME "VK_EXT_shader_stencil_export"
@@ -7483,7 +7560,6 @@
 
 #define VK_EXT_VALIDATION_CACHE_SPEC_VERSION 1
 #define VK_EXT_VALIDATION_CACHE_EXTENSION_NAME "VK_EXT_validation_cache"
-#define VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT VK_DEBUG_REPORT_OBJECT_TYPE_VALIDATION_CACHE_EXT_EXT
 
 
 typedef enum VkValidationCacheHeaderVersionEXT {
@@ -7734,7 +7810,7 @@
 
 
 #define VK_EXT_vertex_attribute_divisor 1
-#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 2
+#define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_SPEC_VERSION 3
 #define VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME "VK_EXT_vertex_attribute_divisor"
 
 typedef struct VkPhysicalDeviceVertexAttributeDivisorPropertiesEXT {
@@ -7755,6 +7831,13 @@
     const VkVertexInputBindingDivisorDescriptionEXT*    pVertexBindingDivisors;
 } VkPipelineVertexInputDivisorStateCreateInfoEXT;
 
+typedef struct VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT {
+    VkStructureType    sType;
+    void*              pNext;
+    VkBool32           vertexAttributeInstanceRateDivisor;
+    VkBool32           vertexAttributeInstanceRateZeroDivisor;
+} VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT;
+
 
 
 #define VK_NV_shader_subgroup_partitioned 1
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 96c5563..b32977a 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -165,8 +165,13 @@
     std::lock_guard<std::mutex> lock(mutex_);
     if (--refcount_ == 0) {
         ALOGV("closing layer library '%s'", path_.c_str());
-        dlclose(dlhandle_);
-        dlhandle_ = nullptr;
+        std::string error_msg;
+        if (!android::CloseNativeLibrary(dlhandle_, native_bridge_, &error_msg)) {
+            ALOGE("failed to unload library '%s': %s", path_.c_str(), error_msg.c_str());
+            refcount_++;
+        } else {
+           dlhandle_ = nullptr;
+        }
     }
 }